blob: 6f52a60bc212c22cca0ccdba9e3a649b839bd1be [file] [log] [blame]
Thomas Gleixner1a59d1b82019-05-27 08:55:05 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +00002/*
3 * Firmware Assisted dump: A robust mechanism to get reliable kernel crash
4 * dump with assistance from firmware. This approach does not use kexec,
5 * instead firmware assists in booting the kdump kernel while preserving
6 * memory contents. The most of the code implementation has been adapted
7 * from phyp assisted dump implementation written by Linas Vepstas and
8 * Manish Ahuja
9 *
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000010 * Copyright 2011 IBM Corporation
11 * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
12 */
13
14#undef DEBUG
15#define pr_fmt(fmt) "fadump: " fmt
16
17#include <linux/string.h>
18#include <linux/memblock.h>
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +000019#include <linux/delay.h>
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +000020#include <linux/seq_file.h>
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +000021#include <linux/crash_dump.h>
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +000022#include <linux/kobject.h>
23#include <linux/sysfs.h>
Hari Bathinia5818312018-08-18 02:10:56 +053024#include <linux/slab.h>
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +053025#include <linux/cma.h>
Christophe Leroy45d0ba52019-04-26 05:59:47 +000026#include <linux/hugetlb.h>
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000027
Michael Ellerman7644d582017-02-10 12:04:56 +110028#include <asm/debugfs.h>
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000029#include <asm/page.h>
30#include <asm/prom.h>
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000031#include <asm/fadump.h>
Hari Bathinica986d72019-09-11 20:16:21 +053032#include <asm/fadump-internal.h>
Stephen Rothwellcad3c832012-03-30 14:01:07 +000033#include <asm/setup.h>
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000034
35static struct fw_dump fw_dump;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +000036
Hari Bathinib2a815a2019-09-11 20:25:49 +053037static void __init fadump_reserve_crash_area(u64 base);
38
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +000039static DEFINE_MUTEX(fadump_mutex);
Hari Bathinie4fc48f2019-09-11 20:25:05 +053040struct fadump_mrange_info crash_mrange_info = { "crash", NULL, 0, 0, 0 };
Hari Bathinidda9dbf2019-09-11 20:25:36 +053041struct fadump_mrange_info reserved_mrange_info = { "reserved", NULL, 0, 0, 0 };
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000042
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +053043#ifdef CONFIG_CMA
Hari Bathini0226e552019-09-11 20:18:14 +053044static struct cma *fadump_cma;
45
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +053046/*
47 * fadump_cma_init() - Initialize CMA area from a fadump reserved memory
48 *
49 * This function initializes CMA area from fadump reserved memory.
50 * The total size of fadump reserved memory covers for boot memory size
51 * + cpu data size + hpte size and metadata.
52 * Initialize only the area equivalent to boot memory size for CMA use.
53 * The reamining portion of fadump reserved memory will be not given
54 * to CMA and pages for thoes will stay reserved. boot memory size is
55 * aligned per CMA requirement to satisy cma_init_reserved_mem() call.
56 * But for some reason even if it fails we still have the memory reservation
57 * with us and we can still continue doing fadump.
58 */
59int __init fadump_cma_init(void)
60{
61 unsigned long long base, size;
62 int rc;
63
64 if (!fw_dump.fadump_enabled)
65 return 0;
66
67 /*
68 * Do not use CMA if user has provided fadump=nocma kernel parameter.
69 * Return 1 to continue with fadump old behaviour.
70 */
71 if (fw_dump.nocma)
72 return 1;
73
74 base = fw_dump.reserve_dump_area_start;
75 size = fw_dump.boot_memory_size;
76
77 if (!size)
78 return 0;
79
80 rc = cma_init_reserved_mem(base, size, 0, "fadump_cma", &fadump_cma);
81 if (rc) {
82 pr_err("Failed to init cma area for firmware-assisted dump,%d\n", rc);
83 /*
84 * Though the CMA init has failed we still have memory
85 * reservation with us. The reserved memory will be
86 * blocked from production system usage. Hence return 1,
87 * so that we can continue with fadump.
88 */
89 return 1;
90 }
91
92 /*
93 * So we now have successfully initialized cma area for fadump.
94 */
95 pr_info("Initialized 0x%lx bytes cma area at %ldMB from 0x%lx "
96 "bytes of memory reserved for firmware-assisted dump\n",
97 cma_get_size(fadump_cma),
98 (unsigned long)cma_get_base(fadump_cma) >> 20,
99 fw_dump.reserve_dump_area_size);
100 return 1;
101}
102#else
103static int __init fadump_cma_init(void) { return 1; }
104#endif /* CONFIG_CMA */
105
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000106/* Scan the Firmware Assisted dump configuration details. */
Hari Bathinif3512012019-09-11 20:19:44 +0530107int __init early_init_dt_scan_fw_dump(unsigned long node, const char *uname,
108 int depth, void *data)
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000109{
Hari Bathini41df5922019-09-11 20:20:26 +0530110 if (depth != 1)
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000111 return 0;
112
Hari Bathini41df5922019-09-11 20:20:26 +0530113 if (strcmp(uname, "rtas") == 0) {
114 rtas_fadump_dt_scan(&fw_dump, node);
115 return 1;
116 }
117
118 if (strcmp(uname, "ibm,opal") == 0) {
119 opal_fadump_dt_scan(&fw_dump, node);
120 return 1;
121 }
122
123 return 0;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000124}
125
Hari Bathinieae0dfc2017-06-01 22:51:26 +0530126/*
127 * If fadump is registered, check if the memory provided
Mahesh Salgaonkar0db68962018-08-20 13:47:32 +0530128 * falls within boot memory area and reserved memory area.
Hari Bathinieae0dfc2017-06-01 22:51:26 +0530129 */
Mahesh Salgaonkar0db68962018-08-20 13:47:32 +0530130int is_fadump_memory_area(u64 addr, ulong size)
Hari Bathinieae0dfc2017-06-01 22:51:26 +0530131{
Mahesh Salgaonkar0db68962018-08-20 13:47:32 +0530132 u64 d_start = fw_dump.reserve_dump_area_start;
133 u64 d_end = d_start + fw_dump.reserve_dump_area_size;
134
Hari Bathinieae0dfc2017-06-01 22:51:26 +0530135 if (!fw_dump.dump_registered)
136 return 0;
137
Mahesh Salgaonkar0db68962018-08-20 13:47:32 +0530138 if (((addr + size) > d_start) && (addr <= d_end))
139 return 1;
140
Hari Bathinieae0dfc2017-06-01 22:51:26 +0530141 return (addr + size) > RMA_START && addr <= fw_dump.boot_memory_size;
142}
143
Nicholas Piggin6fcd6ba2017-07-19 16:59:11 +1000144int should_fadump_crash(void)
145{
146 if (!fw_dump.dump_registered || !fw_dump.fadumphdr_addr)
147 return 0;
148 return 1;
149}
150
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000151int is_fadump_active(void)
152{
153 return fw_dump.dump_active;
154}
155
Hari Bathinia5a05b92017-06-01 22:52:10 +0530156/*
Hari Bathini961cf262019-09-11 20:16:36 +0530157 * Returns true, if there are no holes in memory area between d_start to d_end,
158 * false otherwise.
Hari Bathinia5a05b92017-06-01 22:52:10 +0530159 */
Hari Bathini961cf262019-09-11 20:16:36 +0530160static bool is_fadump_mem_area_contiguous(u64 d_start, u64 d_end)
Hari Bathinia5a05b92017-06-01 22:52:10 +0530161{
162 struct memblock_region *reg;
Hari Bathini961cf262019-09-11 20:16:36 +0530163 bool ret = false;
164 u64 start, end;
Hari Bathinia5a05b92017-06-01 22:52:10 +0530165
166 for_each_memblock(memory, reg) {
Hari Bathini961cf262019-09-11 20:16:36 +0530167 start = max_t(u64, d_start, reg->base);
168 end = min_t(u64, d_end, (reg->base + reg->size));
169 if (d_start < end) {
170 /* Memory hole from d_start to start */
171 if (start > d_start)
Hari Bathinia5a05b92017-06-01 22:52:10 +0530172 break;
173
Hari Bathini961cf262019-09-11 20:16:36 +0530174 if (end == d_end) {
175 ret = true;
Hari Bathinia5a05b92017-06-01 22:52:10 +0530176 break;
177 }
178
Hari Bathini961cf262019-09-11 20:16:36 +0530179 d_start = end + 1;
Hari Bathinia5a05b92017-06-01 22:52:10 +0530180 }
181 }
182
183 return ret;
184}
185
Mahesh Salgaonkarf86593b2018-08-20 13:47:24 +0530186/*
Hari Bathini961cf262019-09-11 20:16:36 +0530187 * Returns true, if there are no holes in boot memory area,
188 * false otherwise.
189 */
Hari Bathini7f0ad112019-09-11 20:16:52 +0530190bool is_fadump_boot_mem_contiguous(void)
Hari Bathini961cf262019-09-11 20:16:36 +0530191{
192 return is_fadump_mem_area_contiguous(0, fw_dump.boot_memory_size);
193}
194
195/*
Mahesh Salgaonkarf86593b2018-08-20 13:47:24 +0530196 * Returns true, if there are no holes in reserved memory area,
197 * false otherwise.
198 */
Hari Bathini7f0ad112019-09-11 20:16:52 +0530199bool is_fadump_reserved_mem_contiguous(void)
Mahesh Salgaonkarf86593b2018-08-20 13:47:24 +0530200{
Hari Bathini961cf262019-09-11 20:16:36 +0530201 u64 d_start, d_end;
Mahesh Salgaonkarf86593b2018-08-20 13:47:24 +0530202
Hari Bathini961cf262019-09-11 20:16:36 +0530203 d_start = fw_dump.reserve_dump_area_start;
204 d_end = d_start + fw_dump.reserve_dump_area_size;
205 return is_fadump_mem_area_contiguous(d_start, d_end);
Mahesh Salgaonkarf86593b2018-08-20 13:47:24 +0530206}
207
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000208/* Print firmware assisted dump configurations for debugging purpose. */
209static void fadump_show_config(void)
210{
211 pr_debug("Support for firmware-assisted dump (fadump): %s\n",
212 (fw_dump.fadump_supported ? "present" : "no support"));
213
214 if (!fw_dump.fadump_supported)
215 return;
216
217 pr_debug("Fadump enabled : %s\n",
218 (fw_dump.fadump_enabled ? "yes" : "no"));
219 pr_debug("Dump Active : %s\n",
220 (fw_dump.dump_active ? "yes" : "no"));
221 pr_debug("Dump section sizes:\n");
222 pr_debug(" CPU state data size: %lx\n", fw_dump.cpu_state_data_size);
223 pr_debug(" HPTE region size : %lx\n", fw_dump.hpte_region_size);
224 pr_debug("Boot memory size : %lx\n", fw_dump.boot_memory_size);
225}
226
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000227/**
228 * fadump_calculate_reserve_size(): reserve variable boot area 5% of System RAM
229 *
230 * Function to find the largest memory size we need to reserve during early
231 * boot process. This will be the size of the memory that is required for a
232 * kernel to boot successfully.
233 *
234 * This function has been taken from phyp-assisted dump feature implementation.
235 *
236 * returns larger of 256MB or 5% rounded down to multiples of 256MB.
237 *
238 * TODO: Come up with better approach to find out more accurate memory size
239 * that is required for a kernel to boot successfully.
240 *
241 */
242static inline unsigned long fadump_calculate_reserve_size(void)
243{
Hari Bathini11550dc2017-05-08 15:56:28 -0700244 int ret;
245 unsigned long long base, size;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000246
Hari Bathini81d9eca2017-05-22 15:04:23 +0530247 if (fw_dump.reserve_bootvar)
248 pr_warn("'fadump_reserve_mem=' parameter is deprecated in favor of 'crashkernel=' parameter.\n");
249
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000250 /*
Hari Bathini11550dc2017-05-08 15:56:28 -0700251 * Check if the size is specified through crashkernel= cmdline
Hari Bathinie7467dc2017-05-22 15:04:47 +0530252 * option. If yes, then use that but ignore base as fadump reserves
253 * memory at a predefined offset.
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000254 */
Hari Bathini11550dc2017-05-08 15:56:28 -0700255 ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
256 &size, &base);
257 if (ret == 0 && size > 0) {
Hari Bathini48a316e2017-06-02 13:00:27 +0530258 unsigned long max_size;
259
Hari Bathini81d9eca2017-05-22 15:04:23 +0530260 if (fw_dump.reserve_bootvar)
261 pr_info("Using 'crashkernel=' parameter for memory reservation.\n");
262
Hari Bathini11550dc2017-05-08 15:56:28 -0700263 fw_dump.reserve_bootvar = (unsigned long)size;
Hari Bathini48a316e2017-06-02 13:00:27 +0530264
265 /*
266 * Adjust if the boot memory size specified is above
267 * the upper limit.
268 */
269 max_size = memblock_phys_mem_size() / MAX_BOOT_MEM_RATIO;
270 if (fw_dump.reserve_bootvar > max_size) {
271 fw_dump.reserve_bootvar = max_size;
272 pr_info("Adjusted boot memory size to %luMB\n",
273 (fw_dump.reserve_bootvar >> 20));
274 }
275
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000276 return fw_dump.reserve_bootvar;
Hari Bathini81d9eca2017-05-22 15:04:23 +0530277 } else if (fw_dump.reserve_bootvar) {
278 /*
279 * 'fadump_reserve_mem=' is being used to reserve memory
280 * for firmware-assisted dump.
281 */
282 return fw_dump.reserve_bootvar;
Hari Bathini11550dc2017-05-08 15:56:28 -0700283 }
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000284
285 /* divide by 20 to get 5% of value */
Hari Bathini48a316e2017-06-02 13:00:27 +0530286 size = memblock_phys_mem_size() / 20;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000287
288 /* round it down in multiples of 256 */
289 size = size & ~0x0FFFFFFFUL;
290
291 /* Truncate to memory_limit. We don't want to over reserve the memory.*/
292 if (memory_limit && size > memory_limit)
293 size = memory_limit;
294
295 return (size > MIN_BOOT_MEM ? size : MIN_BOOT_MEM);
296}
297
298/*
299 * Calculate the total memory size required to be reserved for
300 * firmware-assisted dump registration.
301 */
302static unsigned long get_fadump_area_size(void)
303{
304 unsigned long size = 0;
305
306 size += fw_dump.cpu_state_data_size;
307 size += fw_dump.hpte_region_size;
308 size += fw_dump.boot_memory_size;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000309 size += sizeof(struct fadump_crash_info_header);
310 size += sizeof(struct elfhdr); /* ELF core header.*/
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000311 size += sizeof(struct elf_phdr); /* place holder for cpu notes */
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000312 /* Program headers for crash memory regions. */
313 size += sizeof(struct elf_phdr) * (memblock_num_regions(memory) + 2);
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000314
315 size = PAGE_ALIGN(size);
Hari Bathini742a2652019-09-11 20:20:57 +0530316
317 /* This is to hold kernel metadata on platforms that support it */
318 size += (fw_dump.ops->fadump_get_metadata_size ?
319 fw_dump.ops->fadump_get_metadata_size() : 0);
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000320 return size;
321}
322
323int __init fadump_reserve_mem(void)
324{
Hari Bathini579ca1a2019-09-11 20:24:28 +0530325 bool is_memblock_bottom_up = memblock_bottom_up();
326 u64 base, size, mem_boundary, align = PAGE_SIZE;
Hari Bathini6abec122019-09-11 20:20:41 +0530327 int ret = 1;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000328
329 if (!fw_dump.fadump_enabled)
330 return 0;
331
332 if (!fw_dump.fadump_supported) {
Hari Bathini6abec122019-09-11 20:20:41 +0530333 pr_info("Firmware-Assisted Dump is not supported on this hardware\n");
334 goto error_out;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000335 }
Hari Bathini742a2652019-09-11 20:20:57 +0530336
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000337 /*
338 * Initialize boot memory size
339 * If dump is active then we have already calculated the size during
340 * first kernel.
341 */
Hari Bathinif3512012019-09-11 20:19:44 +0530342 if (!fw_dump.dump_active) {
Hari Bathini6abec122019-09-11 20:20:41 +0530343 fw_dump.boot_memory_size =
344 PAGE_ALIGN(fadump_calculate_reserve_size());
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +0530345#ifdef CONFIG_CMA
Hari Bathini579ca1a2019-09-11 20:24:28 +0530346 if (!fw_dump.nocma) {
347 align = FADUMP_CMA_ALIGNMENT;
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +0530348 fw_dump.boot_memory_size =
Hari Bathini579ca1a2019-09-11 20:24:28 +0530349 ALIGN(fw_dump.boot_memory_size, align);
350 }
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +0530351#endif
352 }
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000353
354 /*
355 * Calculate the memory boundary.
356 * If memory_limit is less than actual memory boundary then reserve
357 * the memory for fadump beyond the memory_limit and adjust the
358 * memory_limit accordingly, so that the running kernel can run with
359 * specified memory_limit.
360 */
361 if (memory_limit && memory_limit < memblock_end_of_DRAM()) {
362 size = get_fadump_area_size();
363 if ((memory_limit + size) < memblock_end_of_DRAM())
364 memory_limit += size;
365 else
366 memory_limit = memblock_end_of_DRAM();
367 printk(KERN_INFO "Adjusted memory_limit for firmware-assisted"
Suzuki Poulosea84fcd42012-08-21 01:42:33 +0000368 " dump, now %#016llx\n", memory_limit);
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000369 }
370 if (memory_limit)
Hari Bathini6abec122019-09-11 20:20:41 +0530371 mem_boundary = memory_limit;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000372 else
Hari Bathini6abec122019-09-11 20:20:41 +0530373 mem_boundary = memblock_end_of_DRAM();
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000374
Hari Bathini6abec122019-09-11 20:20:41 +0530375 base = fw_dump.boot_memory_size;
Hari Bathini8255da92019-09-11 20:19:28 +0530376 size = get_fadump_area_size();
377 fw_dump.reserve_dump_area_size = size;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000378 if (fw_dump.dump_active) {
Mahesh Salgaonkarb71a6932018-04-10 19:11:16 +0530379 pr_info("Firmware-assisted dump is active.\n");
380
Hari Bathini85975382018-04-10 19:11:31 +0530381#ifdef CONFIG_HUGETLB_PAGE
382 /*
383 * FADump capture kernel doesn't care much about hugepages.
384 * In fact, handling hugepages in capture kernel is asking for
385 * trouble. So, disable HugeTLB support when fadump is active.
386 */
387 hugetlb_disabled = true;
388#endif
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000389 /*
390 * If last boot has crashed then reserve all the memory
Hari Bathinib2a815a2019-09-11 20:25:49 +0530391 * above boot memory size so that we don't touch it until
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000392 * dump is written to disk by userspace tool. This memory
Hari Bathinib2a815a2019-09-11 20:25:49 +0530393 * can be released for general use by invalidating fadump.
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000394 */
Hari Bathinib2a815a2019-09-11 20:25:49 +0530395 fadump_reserve_crash_area(base);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000396
Hari Bathinif3512012019-09-11 20:19:44 +0530397 pr_debug("fadumphdr_addr = %#016lx\n", fw_dump.fadumphdr_addr);
398 pr_debug("Reserve dump area start address: 0x%lx\n",
399 fw_dump.reserve_dump_area_start);
Hari Bathini8255da92019-09-11 20:19:28 +0530400 } else {
401 /*
Hari Bathinif6e6bed2017-03-17 02:35:26 +0530402 * Reserve memory at an offset closer to bottom of the RAM to
Hari Bathini579ca1a2019-09-11 20:24:28 +0530403 * minimize the impact of memory hot-remove operation.
Hari Bathinif6e6bed2017-03-17 02:35:26 +0530404 */
Hari Bathini579ca1a2019-09-11 20:24:28 +0530405 memblock_set_bottom_up(true);
406 base = memblock_find_in_range(base, mem_boundary, size, align);
Hari Bathini6abec122019-09-11 20:20:41 +0530407
Hari Bathini579ca1a2019-09-11 20:24:28 +0530408 /* Restore the previous allocation mode */
409 memblock_set_bottom_up(is_memblock_bottom_up);
Hari Bathinif6e6bed2017-03-17 02:35:26 +0530410
Hari Bathini579ca1a2019-09-11 20:24:28 +0530411 if (!base) {
Hari Bathini742a2652019-09-11 20:20:57 +0530412 pr_err("Failed to find memory chunk for reservation!\n");
413 goto error_out;
414 }
415 fw_dump.reserve_dump_area_start = base;
416
417 /*
418 * Calculate the kernel metadata address and register it with
419 * f/w if the platform supports.
420 */
421 if (fw_dump.ops->fadump_setup_metadata &&
422 (fw_dump.ops->fadump_setup_metadata(&fw_dump) < 0))
423 goto error_out;
424
425 if (memblock_reserve(base, size)) {
Hari Bathini6abec122019-09-11 20:20:41 +0530426 pr_err("Failed to reserve memory!\n");
427 goto error_out;
428 }
429
430 pr_info("Reserved %lldMB of memory at %#016llx (System RAM: %lldMB)\n",
431 (size >> 20), base, (memblock_phys_mem_size() >> 20));
Hari Bathinif6e6bed2017-03-17 02:35:26 +0530432
Hari Bathini6abec122019-09-11 20:20:41 +0530433 ret = fadump_cma_init();
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +0530434 }
Hari Bathini6abec122019-09-11 20:20:41 +0530435
436 return ret;
437error_out:
438 fw_dump.fadump_enabled = 0;
439 return 0;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000440}
441
Srikar Dronamraju1e76609c2016-10-07 16:59:21 -0700442unsigned long __init arch_reserved_kernel_pages(void)
443{
444 return memblock_reserved_size() / PAGE_SIZE;
445}
446
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000447/* Look for fadump= cmdline option. */
448static int __init early_fadump_param(char *p)
449{
450 if (!p)
451 return 1;
452
453 if (strncmp(p, "on", 2) == 0)
454 fw_dump.fadump_enabled = 1;
455 else if (strncmp(p, "off", 3) == 0)
456 fw_dump.fadump_enabled = 0;
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +0530457 else if (strncmp(p, "nocma", 5) == 0) {
458 fw_dump.fadump_enabled = 1;
459 fw_dump.nocma = 1;
460 }
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000461
462 return 0;
463}
464early_param("fadump", early_fadump_param);
465
Hari Bathini81d9eca2017-05-22 15:04:23 +0530466/*
467 * Look for fadump_reserve_mem= cmdline option
468 * TODO: Remove references to 'fadump_reserve_mem=' parameter,
469 * the sooner 'crashkernel=' parameter is accustomed to.
470 */
471static int __init early_fadump_reserve_mem(char *p)
472{
473 if (p)
474 fw_dump.reserve_bootvar = memparse(p, &p);
475 return 0;
476}
477early_param("fadump_reserve_mem", early_fadump_reserve_mem);
478
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000479void crash_fadump(struct pt_regs *regs, const char *str)
480{
481 struct fadump_crash_info_header *fdh = NULL;
Mahesh Salgaonkarf2a5e8f2016-10-24 23:51:51 +0530482 int old_cpu, this_cpu;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000483
Nicholas Piggin6fcd6ba2017-07-19 16:59:11 +1000484 if (!should_fadump_crash())
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000485 return;
486
Mahesh Salgaonkarf2a5e8f2016-10-24 23:51:51 +0530487 /*
488 * old_cpu == -1 means this is the first CPU which has come here,
489 * go ahead and trigger fadump.
490 *
491 * old_cpu != -1 means some other CPU has already on it's way
492 * to trigger fadump, just keep looping here.
493 */
494 this_cpu = smp_processor_id();
495 old_cpu = cmpxchg(&crashing_cpu, -1, this_cpu);
496
497 if (old_cpu != -1) {
498 /*
499 * We can't loop here indefinitely. Wait as long as fadump
500 * is in force. If we race with fadump un-registration this
501 * loop will break and then we go down to normal panic path
502 * and reboot. If fadump is in force the first crashing
503 * cpu will definitely trigger fadump.
504 */
505 while (fw_dump.dump_registered)
506 cpu_relax();
507 return;
508 }
509
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000510 fdh = __va(fw_dump.fadumphdr_addr);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000511 fdh->crashing_cpu = crashing_cpu;
512 crash_save_vmcoreinfo();
513
514 if (regs)
515 fdh->regs = *regs;
516 else
517 ppc_save_regs(&fdh->regs);
518
Rasmus Villemoesa0512162016-01-20 15:00:13 -0800519 fdh->online_mask = *cpu_online_mask;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000520
Hari Bathini41a65d12019-09-11 20:18:57 +0530521 fw_dump.ops->fadump_trigger(fdh, str);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000522}
523
Hari Bathini7f0ad112019-09-11 20:16:52 +0530524u32 *fadump_regs_to_elf_notes(u32 *buf, struct pt_regs *regs)
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000525{
526 struct elf_prstatus prstatus;
527
528 memset(&prstatus, 0, sizeof(prstatus));
529 /*
530 * FIXME: How do i get PID? Do I really need it?
531 * prstatus.pr_pid = ????
532 */
533 elf_core_copy_kernel_regs(&prstatus.pr_reg, regs);
Hari Bathini22bd0172017-05-08 15:56:24 -0700534 buf = append_elf_note(buf, CRASH_CORE_NOTE_NAME, NT_PRSTATUS,
535 &prstatus, sizeof(prstatus));
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000536 return buf;
537}
538
Hari Bathini7f0ad112019-09-11 20:16:52 +0530539void fadump_update_elfcore_header(char *bufp)
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000540{
541 struct elfhdr *elf;
542 struct elf_phdr *phdr;
543
544 elf = (struct elfhdr *)bufp;
545 bufp += sizeof(struct elfhdr);
546
547 /* First note is a place holder for cpu notes info. */
548 phdr = (struct elf_phdr *)bufp;
549
550 if (phdr->p_type == PT_NOTE) {
Hari Bathini961cf262019-09-11 20:16:36 +0530551 phdr->p_paddr = __pa(fw_dump.cpu_notes_buf_vaddr);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000552 phdr->p_offset = phdr->p_paddr;
553 phdr->p_filesz = fw_dump.cpu_notes_buf_size;
554 phdr->p_memsz = fw_dump.cpu_notes_buf_size;
555 }
556 return;
557}
558
Hari Bathini961cf262019-09-11 20:16:36 +0530559static void *fadump_alloc_buffer(unsigned long size)
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000560{
Hari Bathini72aa6512019-09-11 20:17:56 +0530561 unsigned long count, i;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000562 struct page *page;
Hari Bathini72aa6512019-09-11 20:17:56 +0530563 void *vaddr;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000564
Hari Bathini72aa6512019-09-11 20:17:56 +0530565 vaddr = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000566 if (!vaddr)
567 return NULL;
568
Hari Bathini72aa6512019-09-11 20:17:56 +0530569 count = PAGE_ALIGN(size) / PAGE_SIZE;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000570 page = virt_to_page(vaddr);
571 for (i = 0; i < count; i++)
Hari Bathini72aa6512019-09-11 20:17:56 +0530572 mark_page_reserved(page + i);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000573 return vaddr;
574}
575
Hari Bathini961cf262019-09-11 20:16:36 +0530576static void fadump_free_buffer(unsigned long vaddr, unsigned long size)
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000577{
Hari Bathini72aa6512019-09-11 20:17:56 +0530578 free_reserved_area((void *)vaddr, (void *)(vaddr + size), -1, NULL);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000579}
580
Hari Bathini7f0ad112019-09-11 20:16:52 +0530581s32 fadump_setup_cpu_notes_buf(u32 num_cpus)
Hari Bathini961cf262019-09-11 20:16:36 +0530582{
583 /* Allocate buffer to hold cpu crash notes. */
584 fw_dump.cpu_notes_buf_size = num_cpus * sizeof(note_buf_t);
585 fw_dump.cpu_notes_buf_size = PAGE_ALIGN(fw_dump.cpu_notes_buf_size);
586 fw_dump.cpu_notes_buf_vaddr =
587 (unsigned long)fadump_alloc_buffer(fw_dump.cpu_notes_buf_size);
588 if (!fw_dump.cpu_notes_buf_vaddr) {
589 pr_err("Failed to allocate %ld bytes for CPU notes buffer\n",
590 fw_dump.cpu_notes_buf_size);
591 return -ENOMEM;
592 }
593
594 pr_debug("Allocated buffer for cpu notes of size %ld at 0x%lx\n",
595 fw_dump.cpu_notes_buf_size,
596 fw_dump.cpu_notes_buf_vaddr);
597 return 0;
598}
599
Hari Bathini7f0ad112019-09-11 20:16:52 +0530600void fadump_free_cpu_notes_buf(void)
Hari Bathini961cf262019-09-11 20:16:36 +0530601{
602 if (!fw_dump.cpu_notes_buf_vaddr)
603 return;
604
605 fadump_free_buffer(fw_dump.cpu_notes_buf_vaddr,
606 fw_dump.cpu_notes_buf_size);
607 fw_dump.cpu_notes_buf_vaddr = 0;
608 fw_dump.cpu_notes_buf_size = 0;
609}
610
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530611static void fadump_free_mem_ranges(struct fadump_mrange_info *mrange_info)
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530612{
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530613 kfree(mrange_info->mem_ranges);
614 mrange_info->mem_ranges = NULL;
615 mrange_info->mem_ranges_sz = 0;
616 mrange_info->max_mem_ranges = 0;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530617}
618
619/*
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530620 * Allocate or reallocate mem_ranges array in incremental units
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530621 * of PAGE_SIZE.
622 */
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530623static int fadump_alloc_mem_ranges(struct fadump_mrange_info *mrange_info)
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530624{
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530625 struct fadump_memory_range *new_array;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530626 u64 new_size;
627
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530628 new_size = mrange_info->mem_ranges_sz + PAGE_SIZE;
629 pr_debug("Allocating %llu bytes of memory for %s memory ranges\n",
630 new_size, mrange_info->name);
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530631
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530632 new_array = krealloc(mrange_info->mem_ranges, new_size, GFP_KERNEL);
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530633 if (new_array == NULL) {
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530634 pr_err("Insufficient memory for setting up %s memory ranges\n",
635 mrange_info->name);
636 fadump_free_mem_ranges(mrange_info);
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530637 return -ENOMEM;
638 }
639
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530640 mrange_info->mem_ranges = new_array;
641 mrange_info->mem_ranges_sz = new_size;
642 mrange_info->max_mem_ranges = (new_size /
643 sizeof(struct fadump_memory_range));
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530644 return 0;
645}
646
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530647static inline int fadump_add_mem_range(struct fadump_mrange_info *mrange_info,
648 u64 base, u64 end)
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000649{
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530650 struct fadump_memory_range *mem_ranges = mrange_info->mem_ranges;
Hari Bathiniced1bf52018-08-07 02:12:54 +0530651 bool is_adjacent = false;
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530652 u64 start, size;
Hari Bathiniced1bf52018-08-07 02:12:54 +0530653
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000654 if (base == end)
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530655 return 0;
656
Hari Bathiniced1bf52018-08-07 02:12:54 +0530657 /*
658 * Fold adjacent memory ranges to bring down the memory ranges/
659 * PT_LOAD segments count.
660 */
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530661 if (mrange_info->mem_range_cnt) {
662 start = mem_ranges[mrange_info->mem_range_cnt - 1].base;
663 size = mem_ranges[mrange_info->mem_range_cnt - 1].size;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530664
Hari Bathiniced1bf52018-08-07 02:12:54 +0530665 if ((start + size) == base)
666 is_adjacent = true;
667 }
668 if (!is_adjacent) {
669 /* resize the array on reaching the limit */
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530670 if (mrange_info->mem_range_cnt == mrange_info->max_mem_ranges) {
Hari Bathiniced1bf52018-08-07 02:12:54 +0530671 int ret;
672
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530673 ret = fadump_alloc_mem_ranges(mrange_info);
Hari Bathiniced1bf52018-08-07 02:12:54 +0530674 if (ret)
675 return ret;
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530676
677 /* Update to the new resized array */
678 mem_ranges = mrange_info->mem_ranges;
Hari Bathiniced1bf52018-08-07 02:12:54 +0530679 }
680
681 start = base;
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530682 mem_ranges[mrange_info->mem_range_cnt].base = start;
683 mrange_info->mem_range_cnt++;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530684 }
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000685
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530686 mem_ranges[mrange_info->mem_range_cnt - 1].size = (end - start);
687 pr_debug("%s_memory_range[%d] [%#016llx-%#016llx], %#llx bytes\n",
688 mrange_info->name, (mrange_info->mem_range_cnt - 1),
689 start, end - 1, (end - start));
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530690 return 0;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000691}
692
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530693static int fadump_exclude_reserved_area(u64 start, u64 end)
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000694{
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530695 u64 ra_start, ra_end;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530696 int ret = 0;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000697
698 ra_start = fw_dump.reserve_dump_area_start;
699 ra_end = ra_start + fw_dump.reserve_dump_area_size;
700
701 if ((ra_start < end) && (ra_end > start)) {
702 if ((start < ra_start) && (end > ra_end)) {
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530703 ret = fadump_add_mem_range(&crash_mrange_info,
704 start, ra_start);
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530705 if (ret)
706 return ret;
707
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530708 ret = fadump_add_mem_range(&crash_mrange_info,
709 ra_end, end);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000710 } else if (start < ra_start) {
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530711 ret = fadump_add_mem_range(&crash_mrange_info,
712 start, ra_start);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000713 } else if (ra_end < end) {
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530714 ret = fadump_add_mem_range(&crash_mrange_info,
715 ra_end, end);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000716 }
717 } else
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530718 ret = fadump_add_mem_range(&crash_mrange_info, start, end);
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530719
720 return ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000721}
722
723static int fadump_init_elfcore_header(char *bufp)
724{
725 struct elfhdr *elf;
726
727 elf = (struct elfhdr *) bufp;
728 bufp += sizeof(struct elfhdr);
729 memcpy(elf->e_ident, ELFMAG, SELFMAG);
730 elf->e_ident[EI_CLASS] = ELF_CLASS;
731 elf->e_ident[EI_DATA] = ELF_DATA;
732 elf->e_ident[EI_VERSION] = EV_CURRENT;
733 elf->e_ident[EI_OSABI] = ELF_OSABI;
734 memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
735 elf->e_type = ET_CORE;
736 elf->e_machine = ELF_ARCH;
737 elf->e_version = EV_CURRENT;
738 elf->e_entry = 0;
739 elf->e_phoff = sizeof(struct elfhdr);
740 elf->e_shoff = 0;
Daniel Axtensd8bced22016-09-06 15:32:42 +1000741#if defined(_CALL_ELF)
742 elf->e_flags = _CALL_ELF;
743#else
744 elf->e_flags = 0;
745#endif
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000746 elf->e_ehsize = sizeof(struct elfhdr);
747 elf->e_phentsize = sizeof(struct elf_phdr);
748 elf->e_phnum = 0;
749 elf->e_shentsize = 0;
750 elf->e_shnum = 0;
751 elf->e_shstrndx = 0;
752
753 return 0;
754}
755
756/*
757 * Traverse through memblock structure and setup crash memory ranges. These
758 * ranges will be used create PT_LOAD program headers in elfcore header.
759 */
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530760static int fadump_setup_crash_memory_ranges(void)
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000761{
762 struct memblock_region *reg;
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530763 u64 start, end;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530764 int ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000765
766 pr_debug("Setup crash memory ranges.\n");
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530767 crash_mrange_info.mem_range_cnt = 0;
Hari Bathiniced1bf52018-08-07 02:12:54 +0530768
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000769 /*
770 * add the first memory chunk (RMA_START through boot_memory_size) as
771 * a separate memory chunk. The reason is, at the time crash firmware
772 * will move the content of this memory chunk to different location
773 * specified during fadump registration. We need to create a separate
774 * program header for this chunk with the correct offset.
775 */
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530776 ret = fadump_add_mem_range(&crash_mrange_info,
777 RMA_START, fw_dump.boot_memory_size);
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530778 if (ret)
779 return ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000780
781 for_each_memblock(memory, reg) {
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530782 start = (u64)reg->base;
783 end = start + (u64)reg->size;
Hari Bathinia77af5522017-06-01 22:50:38 +0530784
785 /*
786 * skip the first memory chunk that is already added (RMA_START
787 * through boot_memory_size). This logic needs a relook if and
788 * when RMA_START changes to a non-zero value.
789 */
790 BUILD_BUG_ON(RMA_START != 0);
791 if (start < fw_dump.boot_memory_size) {
792 if (end > fw_dump.boot_memory_size)
793 start = fw_dump.boot_memory_size;
794 else
795 continue;
796 }
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000797
798 /* add this range excluding the reserved dump area. */
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530799 ret = fadump_exclude_reserved_area(start, end);
800 if (ret)
801 return ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000802 }
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530803
804 return 0;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000805}
806
Mahesh Salgaonkard34c5f22012-02-16 01:14:53 +0000807/*
808 * If the given physical address falls within the boot memory region then
809 * return the relocated address that points to the dump region reserved
810 * for saving initial boot memory contents.
811 */
812static inline unsigned long fadump_relocate(unsigned long paddr)
813{
814 if (paddr > RMA_START && paddr < fw_dump.boot_memory_size)
Hari Bathini41a65d12019-09-11 20:18:57 +0530815 return fw_dump.boot_mem_dest_addr + paddr;
Mahesh Salgaonkard34c5f22012-02-16 01:14:53 +0000816 else
817 return paddr;
818}
819
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000820static int fadump_create_elfcore_headers(char *bufp)
821{
822 struct elfhdr *elf;
823 struct elf_phdr *phdr;
824 int i;
825
826 fadump_init_elfcore_header(bufp);
827 elf = (struct elfhdr *)bufp;
828 bufp += sizeof(struct elfhdr);
829
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000830 /*
831 * setup ELF PT_NOTE, place holder for cpu notes info. The notes info
832 * will be populated during second kernel boot after crash. Hence
833 * this PT_NOTE will always be the first elf note.
834 *
835 * NOTE: Any new ELF note addition should be placed after this note.
836 */
837 phdr = (struct elf_phdr *)bufp;
838 bufp += sizeof(struct elf_phdr);
839 phdr->p_type = PT_NOTE;
840 phdr->p_flags = 0;
841 phdr->p_vaddr = 0;
842 phdr->p_align = 0;
843
844 phdr->p_offset = 0;
845 phdr->p_paddr = 0;
846 phdr->p_filesz = 0;
847 phdr->p_memsz = 0;
848
849 (elf->e_phnum)++;
850
Mahesh Salgaonkard34c5f22012-02-16 01:14:53 +0000851 /* setup ELF PT_NOTE for vmcoreinfo */
852 phdr = (struct elf_phdr *)bufp;
853 bufp += sizeof(struct elf_phdr);
854 phdr->p_type = PT_NOTE;
855 phdr->p_flags = 0;
856 phdr->p_vaddr = 0;
857 phdr->p_align = 0;
858
859 phdr->p_paddr = fadump_relocate(paddr_vmcoreinfo_note());
860 phdr->p_offset = phdr->p_paddr;
Xunlei Pang5203f492017-07-12 14:33:17 -0700861 phdr->p_memsz = phdr->p_filesz = VMCOREINFO_NOTE_SIZE;
Mahesh Salgaonkard34c5f22012-02-16 01:14:53 +0000862
863 /* Increment number of program headers. */
864 (elf->e_phnum)++;
865
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000866 /* setup PT_LOAD sections. */
867
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530868 for (i = 0; i < crash_mrange_info.mem_range_cnt; i++) {
869 u64 mbase, msize;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000870
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530871 mbase = crash_mrange_info.mem_ranges[i].base;
872 msize = crash_mrange_info.mem_ranges[i].size;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000873 if (!msize)
874 continue;
875
876 phdr = (struct elf_phdr *)bufp;
877 bufp += sizeof(struct elf_phdr);
878 phdr->p_type = PT_LOAD;
879 phdr->p_flags = PF_R|PF_W|PF_X;
880 phdr->p_offset = mbase;
881
882 if (mbase == RMA_START) {
883 /*
884 * The entire RMA region will be moved by firmware
885 * to the specified destination_address. Hence set
886 * the correct offset.
887 */
Hari Bathini41a65d12019-09-11 20:18:57 +0530888 phdr->p_offset = fw_dump.boot_mem_dest_addr;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000889 }
890
891 phdr->p_paddr = mbase;
892 phdr->p_vaddr = (unsigned long)__va(mbase);
893 phdr->p_filesz = msize;
894 phdr->p_memsz = msize;
895 phdr->p_align = 0;
896
897 /* Increment number of program headers. */
898 (elf->e_phnum)++;
899 }
900 return 0;
901}
902
903static unsigned long init_fadump_header(unsigned long addr)
904{
905 struct fadump_crash_info_header *fdh;
906
907 if (!addr)
908 return 0;
909
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000910 fdh = __va(addr);
911 addr += sizeof(struct fadump_crash_info_header);
912
913 memset(fdh, 0, sizeof(struct fadump_crash_info_header));
914 fdh->magic_number = FADUMP_CRASH_INFO_MAGIC;
915 fdh->elfcorehdr_addr = addr;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000916 /* We will set the crashing cpu id in crash_fadump() during crash. */
Hari Bathini0226e552019-09-11 20:18:14 +0530917 fdh->crashing_cpu = FADUMP_CPU_UNKNOWN;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000918
919 return addr;
920}
921
Michal Suchanek98b8cd72017-05-27 17:46:15 +0200922static int register_fadump(void)
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000923{
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000924 unsigned long addr;
925 void *vaddr;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530926 int ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000927
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000928 /*
929 * If no memory is reserved then we can not register for firmware-
930 * assisted dump.
931 */
932 if (!fw_dump.reserve_dump_area_size)
Michal Suchanek98b8cd72017-05-27 17:46:15 +0200933 return -ENODEV;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000934
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530935 ret = fadump_setup_crash_memory_ranges();
936 if (ret)
937 return ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000938
Hari Bathini41a65d12019-09-11 20:18:57 +0530939 addr = fw_dump.fadumphdr_addr;
940
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000941 /* Initialize fadump crash info header. */
942 addr = init_fadump_header(addr);
943 vaddr = __va(addr);
944
945 pr_debug("Creating ELF core headers at %#016lx\n", addr);
946 fadump_create_elfcore_headers(vaddr);
947
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000948 /* register the future kernel dump with firmware. */
Hari Bathini41a65d12019-09-11 20:18:57 +0530949 pr_debug("Registering for firmware-assisted kernel dump...\n");
950 return fw_dump.ops->fadump_register(&fw_dump);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000951}
952
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +0000953void fadump_cleanup(void)
954{
Hari Bathini2790d012019-09-11 20:21:16 +0530955 if (!fw_dump.fadump_supported)
956 return;
957
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +0000958 /* Invalidate the registration only if dump is active. */
959 if (fw_dump.dump_active) {
Hari Bathinif3512012019-09-11 20:19:44 +0530960 pr_debug("Invalidating firmware-assisted dump registration\n");
961 fw_dump.ops->fadump_invalidate(&fw_dump);
Mahesh Salgaonkar722cde72018-04-27 11:53:18 +0530962 } else if (fw_dump.dump_registered) {
963 /* Un-register Firmware-assisted dump if it was registered. */
Hari Bathini41a65d12019-09-11 20:18:57 +0530964 fw_dump.ops->fadump_unregister(&fw_dump);
Hari Bathinie4fc48f2019-09-11 20:25:05 +0530965 fadump_free_mem_ranges(&crash_mrange_info);
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +0000966 }
Hari Bathini2790d012019-09-11 20:21:16 +0530967
968 if (fw_dump.ops->fadump_cleanup)
969 fw_dump.ops->fadump_cleanup(&fw_dump);
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +0000970}
971
Hari Bathini68fa6472017-06-02 01:10:10 +0530972static void fadump_free_reserved_memory(unsigned long start_pfn,
973 unsigned long end_pfn)
974{
975 unsigned long pfn;
976 unsigned long time_limit = jiffies + HZ;
977
978 pr_info("freeing reserved memory (0x%llx - 0x%llx)\n",
979 PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
980
981 for (pfn = start_pfn; pfn < end_pfn; pfn++) {
982 free_reserved_page(pfn_to_page(pfn));
983
984 if (time_after(jiffies, time_limit)) {
985 cond_resched();
986 time_limit = jiffies + HZ;
987 }
988 }
989}
990
991/*
992 * Skip memory holes and free memory that was actually reserved.
993 */
Hari Bathinidda9dbf2019-09-11 20:25:36 +0530994static void fadump_release_reserved_area(u64 start, u64 end)
Hari Bathini68fa6472017-06-02 01:10:10 +0530995{
Hari Bathinidda9dbf2019-09-11 20:25:36 +0530996 u64 tstart, tend, spfn, epfn;
Hari Bathini68fa6472017-06-02 01:10:10 +0530997 struct memblock_region *reg;
Hari Bathini68fa6472017-06-02 01:10:10 +0530998
Hari Bathinidda9dbf2019-09-11 20:25:36 +0530999 spfn = PHYS_PFN(start);
1000 epfn = PHYS_PFN(end);
Hari Bathini68fa6472017-06-02 01:10:10 +05301001 for_each_memblock(memory, reg) {
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301002 tstart = max_t(u64, spfn, memblock_region_memory_base_pfn(reg));
1003 tend = min_t(u64, epfn, memblock_region_memory_end_pfn(reg));
Hari Bathini68fa6472017-06-02 01:10:10 +05301004 if (tstart < tend) {
1005 fadump_free_reserved_memory(tstart, tend);
1006
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301007 if (tend == epfn)
Hari Bathini68fa6472017-06-02 01:10:10 +05301008 break;
1009
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301010 spfn = tend;
Hari Bathini68fa6472017-06-02 01:10:10 +05301011 }
1012 }
1013}
1014
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001015/*
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301016 * Sort the mem ranges in-place and merge adjacent ranges
1017 * to minimize the memory ranges count.
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001018 */
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301019static void sort_and_merge_mem_ranges(struct fadump_mrange_info *mrange_info)
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001020{
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301021 struct fadump_memory_range *mem_ranges;
1022 struct fadump_memory_range tmp_range;
1023 u64 base, size;
1024 int i, j, idx;
1025
1026 if (!reserved_mrange_info.mem_range_cnt)
1027 return;
1028
1029 /* Sort the memory ranges */
1030 mem_ranges = mrange_info->mem_ranges;
1031 for (i = 0; i < mrange_info->mem_range_cnt; i++) {
1032 idx = i;
1033 for (j = (i + 1); j < mrange_info->mem_range_cnt; j++) {
1034 if (mem_ranges[idx].base > mem_ranges[j].base)
1035 idx = j;
1036 }
1037 if (idx != i) {
1038 tmp_range = mem_ranges[idx];
1039 mem_ranges[idx] = mem_ranges[i];
1040 mem_ranges[i] = tmp_range;
1041 }
1042 }
1043
1044 /* Merge adjacent reserved ranges */
1045 idx = 0;
1046 for (i = 1; i < mrange_info->mem_range_cnt; i++) {
1047 base = mem_ranges[i-1].base;
1048 size = mem_ranges[i-1].size;
1049 if (mem_ranges[i].base == (base + size))
1050 mem_ranges[idx].size += mem_ranges[i].size;
1051 else {
1052 idx++;
1053 if (i == idx)
1054 continue;
1055
1056 mem_ranges[idx] = mem_ranges[i];
1057 }
1058 }
1059 mrange_info->mem_range_cnt = idx + 1;
1060}
1061
1062/*
1063 * Scan reserved-ranges to consider them while reserving/releasing
1064 * memory for FADump.
1065 */
1066static inline int fadump_scan_reserved_mem_ranges(void)
1067{
1068 struct device_node *root;
1069 const __be32 *prop;
1070 int len, ret = -1;
1071 unsigned long i;
1072
1073 root = of_find_node_by_path("/");
1074 if (!root)
1075 return ret;
1076
1077 prop = of_get_property(root, "reserved-ranges", &len);
1078 if (!prop)
1079 return ret;
1080
1081 /*
1082 * Each reserved range is an (address,size) pair, 2 cells each,
1083 * totalling 4 cells per range.
1084 */
1085 for (i = 0; i < len / (sizeof(*prop) * 4); i++) {
1086 u64 base, size;
1087
1088 base = of_read_number(prop + (i * 4) + 0, 2);
1089 size = of_read_number(prop + (i * 4) + 2, 2);
1090
1091 if (size) {
1092 ret = fadump_add_mem_range(&reserved_mrange_info,
1093 base, base + size);
1094 if (ret < 0) {
1095 pr_warn("some reserved ranges are ignored!\n");
1096 break;
1097 }
1098 }
1099 }
1100
1101 return ret;
1102}
1103
1104/*
1105 * Release the memory that was reserved during early boot to preserve the
1106 * crash'ed kernel's memory contents except reserved dump area (permanent
1107 * reservation) and reserved ranges used by F/W. The released memory will
1108 * be available for general use.
1109 */
1110static void fadump_release_memory(u64 begin, u64 end)
1111{
1112 u64 ra_start, ra_end, tstart;
1113 int i, ret;
1114
1115 fadump_scan_reserved_mem_ranges();
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001116
1117 ra_start = fw_dump.reserve_dump_area_start;
1118 ra_end = ra_start + fw_dump.reserve_dump_area_size;
1119
Hari Bathini68fa6472017-06-02 01:10:10 +05301120 /*
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301121 * Add reserved dump area to reserved ranges list
1122 * and exclude all these ranges while releasing memory.
Hari Bathini68fa6472017-06-02 01:10:10 +05301123 */
Hari Bathinidda9dbf2019-09-11 20:25:36 +05301124 ret = fadump_add_mem_range(&reserved_mrange_info, ra_start, ra_end);
1125 if (ret != 0) {
1126 /*
1127 * Not enough memory to setup reserved ranges but the system is
1128 * running shortage of memory. So, release all the memory except
1129 * Reserved dump area (reused for next fadump registration).
1130 */
1131 if (begin < ra_end && end > ra_start) {
1132 if (begin < ra_start)
1133 fadump_release_reserved_area(begin, ra_start);
1134 if (end > ra_end)
1135 fadump_release_reserved_area(ra_end, end);
1136 } else
1137 fadump_release_reserved_area(begin, end);
1138
1139 return;
1140 }
1141
1142 /* Get the reserved ranges list in order first. */
1143 sort_and_merge_mem_ranges(&reserved_mrange_info);
1144
1145 /* Exclude reserved ranges and release remaining memory */
1146 tstart = begin;
1147 for (i = 0; i < reserved_mrange_info.mem_range_cnt; i++) {
1148 ra_start = reserved_mrange_info.mem_ranges[i].base;
1149 ra_end = ra_start + reserved_mrange_info.mem_ranges[i].size;
1150
1151 if (tstart >= ra_end)
1152 continue;
1153
1154 if (tstart < ra_start)
1155 fadump_release_reserved_area(tstart, ra_start);
1156 tstart = ra_end;
1157 }
1158
1159 if (tstart < end)
1160 fadump_release_reserved_area(tstart, end);
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001161}
1162
1163static void fadump_invalidate_release_mem(void)
1164{
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001165 mutex_lock(&fadump_mutex);
1166 if (!fw_dump.dump_active) {
1167 mutex_unlock(&fadump_mutex);
1168 return;
1169 }
1170
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001171 fadump_cleanup();
1172 mutex_unlock(&fadump_mutex);
1173
Hari Bathini8255da92019-09-11 20:19:28 +05301174 fadump_release_memory(fw_dump.boot_memory_size, memblock_end_of_DRAM());
Hari Bathini961cf262019-09-11 20:16:36 +05301175 fadump_free_cpu_notes_buf();
1176
Hari Bathinia4e2e2c2019-09-11 20:23:28 +05301177 /*
1178 * Setup kernel metadata and initialize the kernel dump
1179 * memory structure for FADump re-registration.
1180 */
1181 if (fw_dump.ops->fadump_setup_metadata &&
1182 (fw_dump.ops->fadump_setup_metadata(&fw_dump) < 0))
1183 pr_warn("Failed to setup kernel metadata!\n");
Hari Bathini41a65d12019-09-11 20:18:57 +05301184 fw_dump.ops->fadump_init_mem_struct(&fw_dump);
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001185}
1186
1187static ssize_t fadump_release_memory_store(struct kobject *kobj,
1188 struct kobj_attribute *attr,
1189 const char *buf, size_t count)
1190{
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001191 int input = -1;
1192
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001193 if (!fw_dump.dump_active)
1194 return -EPERM;
1195
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001196 if (kstrtoint(buf, 0, &input))
1197 return -EINVAL;
1198
1199 if (input == 1) {
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001200 /*
1201 * Take away the '/proc/vmcore'. We are releasing the dump
1202 * memory, hence it will not be valid anymore.
1203 */
Michael Ellerman2685f822016-09-30 10:51:46 +10001204#ifdef CONFIG_PROC_VMCORE
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001205 vmcore_cleanup();
Michael Ellerman2685f822016-09-30 10:51:46 +10001206#endif
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001207 fadump_invalidate_release_mem();
1208
1209 } else
1210 return -EINVAL;
1211 return count;
1212}
1213
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001214static ssize_t fadump_enabled_show(struct kobject *kobj,
1215 struct kobj_attribute *attr,
1216 char *buf)
1217{
1218 return sprintf(buf, "%d\n", fw_dump.fadump_enabled);
1219}
1220
1221static ssize_t fadump_register_show(struct kobject *kobj,
1222 struct kobj_attribute *attr,
1223 char *buf)
1224{
1225 return sprintf(buf, "%d\n", fw_dump.dump_registered);
1226}
1227
1228static ssize_t fadump_register_store(struct kobject *kobj,
1229 struct kobj_attribute *attr,
1230 const char *buf, size_t count)
1231{
1232 int ret = 0;
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001233 int input = -1;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001234
Hari Bathinif3512012019-09-11 20:19:44 +05301235 if (!fw_dump.fadump_enabled || fw_dump.dump_active)
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001236 return -EPERM;
1237
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001238 if (kstrtoint(buf, 0, &input))
1239 return -EINVAL;
1240
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001241 mutex_lock(&fadump_mutex);
1242
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001243 switch (input) {
1244 case 0:
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001245 if (fw_dump.dump_registered == 0) {
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001246 goto unlock_out;
1247 }
Hari Bathinif3512012019-09-11 20:19:44 +05301248
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001249 /* Un-register Firmware-assisted dump */
Hari Bathini41a65d12019-09-11 20:18:57 +05301250 pr_debug("Un-register firmware-assisted dump\n");
1251 fw_dump.ops->fadump_unregister(&fw_dump);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001252 break;
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001253 case 1:
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001254 if (fw_dump.dump_registered == 1) {
Hari Bathini0823c682018-09-14 19:36:02 +05301255 /* Un-register Firmware-assisted dump */
Hari Bathini41a65d12019-09-11 20:18:57 +05301256 fw_dump.ops->fadump_unregister(&fw_dump);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001257 }
1258 /* Register Firmware-assisted dump */
Michal Suchanek98b8cd72017-05-27 17:46:15 +02001259 ret = register_fadump();
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001260 break;
1261 default:
1262 ret = -EINVAL;
1263 break;
1264 }
1265
1266unlock_out:
1267 mutex_unlock(&fadump_mutex);
1268 return ret < 0 ? ret : count;
1269}
1270
1271static int fadump_region_show(struct seq_file *m, void *private)
1272{
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001273 if (!fw_dump.fadump_enabled)
1274 return 0;
1275
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001276 mutex_lock(&fadump_mutex);
Hari Bathinif3512012019-09-11 20:19:44 +05301277 fw_dump.ops->fadump_region_show(&fw_dump, m);
1278 mutex_unlock(&fadump_mutex);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001279 return 0;
1280}
1281
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001282static struct kobj_attribute fadump_release_attr = __ATTR(fadump_release_mem,
1283 0200, NULL,
1284 fadump_release_memory_store);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001285static struct kobj_attribute fadump_attr = __ATTR(fadump_enabled,
1286 0444, fadump_enabled_show,
1287 NULL);
1288static struct kobj_attribute fadump_register_attr = __ATTR(fadump_registered,
1289 0644, fadump_register_show,
1290 fadump_register_store);
1291
Yangtao Lif6cee262018-11-05 10:01:19 -05001292DEFINE_SHOW_ATTRIBUTE(fadump_region);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001293
1294static void fadump_init_files(void)
1295{
1296 struct dentry *debugfs_file;
1297 int rc = 0;
1298
1299 rc = sysfs_create_file(kernel_kobj, &fadump_attr.attr);
1300 if (rc)
1301 printk(KERN_ERR "fadump: unable to create sysfs file"
1302 " fadump_enabled (%d)\n", rc);
1303
1304 rc = sysfs_create_file(kernel_kobj, &fadump_register_attr.attr);
1305 if (rc)
1306 printk(KERN_ERR "fadump: unable to create sysfs file"
1307 " fadump_registered (%d)\n", rc);
1308
1309 debugfs_file = debugfs_create_file("fadump_region", 0444,
1310 powerpc_debugfs_root, NULL,
1311 &fadump_region_fops);
1312 if (!debugfs_file)
1313 printk(KERN_ERR "fadump: unable to create debugfs file"
1314 " fadump_region\n");
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001315
1316 if (fw_dump.dump_active) {
1317 rc = sysfs_create_file(kernel_kobj, &fadump_release_attr.attr);
1318 if (rc)
1319 printk(KERN_ERR "fadump: unable to create sysfs file"
1320 " fadump_release_mem (%d)\n", rc);
1321 }
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001322 return;
1323}
1324
1325/*
1326 * Prepare for firmware-assisted dump.
1327 */
1328int __init setup_fadump(void)
1329{
1330 if (!fw_dump.fadump_enabled)
1331 return 0;
1332
1333 if (!fw_dump.fadump_supported) {
1334 printk(KERN_ERR "Firmware-assisted dump is not supported on"
1335 " this hardware\n");
1336 return 0;
1337 }
1338
1339 fadump_show_config();
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +00001340 /*
1341 * If dump data is available then see if it is valid and prepare for
1342 * saving it to the disk.
1343 */
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001344 if (fw_dump.dump_active) {
1345 /*
1346 * if dump process fails then invalidate the registration
1347 * and release memory before proceeding for re-registration.
1348 */
Hari Bathinif3512012019-09-11 20:19:44 +05301349 if (fw_dump.ops->fadump_process(&fw_dump) < 0)
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001350 fadump_invalidate_release_mem();
1351 }
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001352 /* Initialize the kernel dump memory structure for FAD registration. */
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +00001353 else if (fw_dump.reserve_dump_area_size)
Hari Bathini41a65d12019-09-11 20:18:57 +05301354 fw_dump.ops->fadump_init_mem_struct(&fw_dump);
Hari Bathinif3512012019-09-11 20:19:44 +05301355
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001356 fadump_init_files();
1357
1358 return 1;
1359}
1360subsys_initcall(setup_fadump);
Hari Bathinib2a815a2019-09-11 20:25:49 +05301361
1362/* Preserve everything above the base address */
1363static void __init fadump_reserve_crash_area(u64 base)
1364{
1365 struct memblock_region *reg;
1366 u64 mstart, msize;
1367
1368 for_each_memblock(memory, reg) {
1369 mstart = reg->base;
1370 msize = reg->size;
1371
1372 if ((mstart + msize) < base)
1373 continue;
1374
1375 if (mstart < base) {
1376 msize -= (base - mstart);
1377 mstart = base;
1378 }
1379
1380 pr_info("Reserving %lluMB of memory at %#016llx for preserving crash data",
1381 (msize >> 20), mstart);
1382 memblock_reserve(mstart, msize);
1383 }
1384}