blob: da751402c6493632f20c4b60d9d5aaabbe9aa69f [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
37static DEFINE_MUTEX(fadump_mutex);
Hari Bathini1bd6a1c2018-08-07 02:12:45 +053038struct fad_crash_memory_ranges *crash_memory_ranges;
39int crash_memory_ranges_size;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +000040int crash_mem_ranges;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +053041int max_crash_mem_ranges;
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
Mahesh Salgaonkarb71a6932018-04-10 19:11:16 +0530323static void __init fadump_reserve_crash_area(unsigned long base,
324 unsigned long size)
325{
326 struct memblock_region *reg;
327 unsigned long mstart, mend, msize;
328
329 for_each_memblock(memory, reg) {
330 mstart = max_t(unsigned long, base, reg->base);
331 mend = reg->base + reg->size;
332 mend = min(base + size, mend);
333
334 if (mstart < mend) {
335 msize = mend - mstart;
336 memblock_reserve(mstart, msize);
337 pr_info("Reserved %ldMB of memory at %#016lx for saving crash dump\n",
338 (msize >> 20), mstart);
339 }
340 }
341}
342
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000343int __init fadump_reserve_mem(void)
344{
Hari Bathini579ca1a2019-09-11 20:24:28 +0530345 bool is_memblock_bottom_up = memblock_bottom_up();
346 u64 base, size, mem_boundary, align = PAGE_SIZE;
Hari Bathini6abec122019-09-11 20:20:41 +0530347 int ret = 1;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000348
349 if (!fw_dump.fadump_enabled)
350 return 0;
351
352 if (!fw_dump.fadump_supported) {
Hari Bathini6abec122019-09-11 20:20:41 +0530353 pr_info("Firmware-Assisted Dump is not supported on this hardware\n");
354 goto error_out;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000355 }
Hari Bathini742a2652019-09-11 20:20:57 +0530356
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000357 /*
358 * Initialize boot memory size
359 * If dump is active then we have already calculated the size during
360 * first kernel.
361 */
Hari Bathinif3512012019-09-11 20:19:44 +0530362 if (!fw_dump.dump_active) {
Hari Bathini6abec122019-09-11 20:20:41 +0530363 fw_dump.boot_memory_size =
364 PAGE_ALIGN(fadump_calculate_reserve_size());
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +0530365#ifdef CONFIG_CMA
Hari Bathini579ca1a2019-09-11 20:24:28 +0530366 if (!fw_dump.nocma) {
367 align = FADUMP_CMA_ALIGNMENT;
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +0530368 fw_dump.boot_memory_size =
Hari Bathini579ca1a2019-09-11 20:24:28 +0530369 ALIGN(fw_dump.boot_memory_size, align);
370 }
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +0530371#endif
372 }
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000373
374 /*
375 * Calculate the memory boundary.
376 * If memory_limit is less than actual memory boundary then reserve
377 * the memory for fadump beyond the memory_limit and adjust the
378 * memory_limit accordingly, so that the running kernel can run with
379 * specified memory_limit.
380 */
381 if (memory_limit && memory_limit < memblock_end_of_DRAM()) {
382 size = get_fadump_area_size();
383 if ((memory_limit + size) < memblock_end_of_DRAM())
384 memory_limit += size;
385 else
386 memory_limit = memblock_end_of_DRAM();
387 printk(KERN_INFO "Adjusted memory_limit for firmware-assisted"
Suzuki Poulosea84fcd42012-08-21 01:42:33 +0000388 " dump, now %#016llx\n", memory_limit);
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000389 }
390 if (memory_limit)
Hari Bathini6abec122019-09-11 20:20:41 +0530391 mem_boundary = memory_limit;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000392 else
Hari Bathini6abec122019-09-11 20:20:41 +0530393 mem_boundary = memblock_end_of_DRAM();
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000394
Hari Bathini6abec122019-09-11 20:20:41 +0530395 base = fw_dump.boot_memory_size;
Hari Bathini8255da92019-09-11 20:19:28 +0530396 size = get_fadump_area_size();
397 fw_dump.reserve_dump_area_size = size;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000398 if (fw_dump.dump_active) {
Mahesh Salgaonkarb71a6932018-04-10 19:11:16 +0530399 pr_info("Firmware-assisted dump is active.\n");
400
Hari Bathini85975382018-04-10 19:11:31 +0530401#ifdef CONFIG_HUGETLB_PAGE
402 /*
403 * FADump capture kernel doesn't care much about hugepages.
404 * In fact, handling hugepages in capture kernel is asking for
405 * trouble. So, disable HugeTLB support when fadump is active.
406 */
407 hugetlb_disabled = true;
408#endif
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000409 /*
410 * If last boot has crashed then reserve all the memory
411 * above boot_memory_size so that we don't touch it until
412 * dump is written to disk by userspace tool. This memory
413 * will be released for general use once the dump is saved.
414 */
Hari Bathini6abec122019-09-11 20:20:41 +0530415 size = mem_boundary - base;
Mahesh Salgaonkarb71a6932018-04-10 19:11:16 +0530416 fadump_reserve_crash_area(base, size);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000417
Hari Bathinif3512012019-09-11 20:19:44 +0530418 pr_debug("fadumphdr_addr = %#016lx\n", fw_dump.fadumphdr_addr);
419 pr_debug("Reserve dump area start address: 0x%lx\n",
420 fw_dump.reserve_dump_area_start);
Hari Bathini8255da92019-09-11 20:19:28 +0530421 } else {
422 /*
Hari Bathinif6e6bed2017-03-17 02:35:26 +0530423 * Reserve memory at an offset closer to bottom of the RAM to
Hari Bathini579ca1a2019-09-11 20:24:28 +0530424 * minimize the impact of memory hot-remove operation.
Hari Bathinif6e6bed2017-03-17 02:35:26 +0530425 */
Hari Bathini579ca1a2019-09-11 20:24:28 +0530426 memblock_set_bottom_up(true);
427 base = memblock_find_in_range(base, mem_boundary, size, align);
Hari Bathini6abec122019-09-11 20:20:41 +0530428
Hari Bathini579ca1a2019-09-11 20:24:28 +0530429 /* Restore the previous allocation mode */
430 memblock_set_bottom_up(is_memblock_bottom_up);
Hari Bathinif6e6bed2017-03-17 02:35:26 +0530431
Hari Bathini579ca1a2019-09-11 20:24:28 +0530432 if (!base) {
Hari Bathini742a2652019-09-11 20:20:57 +0530433 pr_err("Failed to find memory chunk for reservation!\n");
434 goto error_out;
435 }
436 fw_dump.reserve_dump_area_start = base;
437
438 /*
439 * Calculate the kernel metadata address and register it with
440 * f/w if the platform supports.
441 */
442 if (fw_dump.ops->fadump_setup_metadata &&
443 (fw_dump.ops->fadump_setup_metadata(&fw_dump) < 0))
444 goto error_out;
445
446 if (memblock_reserve(base, size)) {
Hari Bathini6abec122019-09-11 20:20:41 +0530447 pr_err("Failed to reserve memory!\n");
448 goto error_out;
449 }
450
451 pr_info("Reserved %lldMB of memory at %#016llx (System RAM: %lldMB)\n",
452 (size >> 20), base, (memblock_phys_mem_size() >> 20));
Hari Bathinif6e6bed2017-03-17 02:35:26 +0530453
Hari Bathini6abec122019-09-11 20:20:41 +0530454 ret = fadump_cma_init();
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +0530455 }
Hari Bathini6abec122019-09-11 20:20:41 +0530456
457 return ret;
458error_out:
459 fw_dump.fadump_enabled = 0;
460 return 0;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000461}
462
Srikar Dronamraju1e76609c2016-10-07 16:59:21 -0700463unsigned long __init arch_reserved_kernel_pages(void)
464{
465 return memblock_reserved_size() / PAGE_SIZE;
466}
467
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000468/* Look for fadump= cmdline option. */
469static int __init early_fadump_param(char *p)
470{
471 if (!p)
472 return 1;
473
474 if (strncmp(p, "on", 2) == 0)
475 fw_dump.fadump_enabled = 1;
476 else if (strncmp(p, "off", 3) == 0)
477 fw_dump.fadump_enabled = 0;
Mahesh Salgaonkara4e92ce2018-08-20 13:47:17 +0530478 else if (strncmp(p, "nocma", 5) == 0) {
479 fw_dump.fadump_enabled = 1;
480 fw_dump.nocma = 1;
481 }
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000482
483 return 0;
484}
485early_param("fadump", early_fadump_param);
486
Hari Bathini81d9eca2017-05-22 15:04:23 +0530487/*
488 * Look for fadump_reserve_mem= cmdline option
489 * TODO: Remove references to 'fadump_reserve_mem=' parameter,
490 * the sooner 'crashkernel=' parameter is accustomed to.
491 */
492static int __init early_fadump_reserve_mem(char *p)
493{
494 if (p)
495 fw_dump.reserve_bootvar = memparse(p, &p);
496 return 0;
497}
498early_param("fadump_reserve_mem", early_fadump_reserve_mem);
499
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000500void crash_fadump(struct pt_regs *regs, const char *str)
501{
502 struct fadump_crash_info_header *fdh = NULL;
Mahesh Salgaonkarf2a5e8f2016-10-24 23:51:51 +0530503 int old_cpu, this_cpu;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000504
Nicholas Piggin6fcd6ba2017-07-19 16:59:11 +1000505 if (!should_fadump_crash())
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000506 return;
507
Mahesh Salgaonkarf2a5e8f2016-10-24 23:51:51 +0530508 /*
509 * old_cpu == -1 means this is the first CPU which has come here,
510 * go ahead and trigger fadump.
511 *
512 * old_cpu != -1 means some other CPU has already on it's way
513 * to trigger fadump, just keep looping here.
514 */
515 this_cpu = smp_processor_id();
516 old_cpu = cmpxchg(&crashing_cpu, -1, this_cpu);
517
518 if (old_cpu != -1) {
519 /*
520 * We can't loop here indefinitely. Wait as long as fadump
521 * is in force. If we race with fadump un-registration this
522 * loop will break and then we go down to normal panic path
523 * and reboot. If fadump is in force the first crashing
524 * cpu will definitely trigger fadump.
525 */
526 while (fw_dump.dump_registered)
527 cpu_relax();
528 return;
529 }
530
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000531 fdh = __va(fw_dump.fadumphdr_addr);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000532 fdh->crashing_cpu = crashing_cpu;
533 crash_save_vmcoreinfo();
534
535 if (regs)
536 fdh->regs = *regs;
537 else
538 ppc_save_regs(&fdh->regs);
539
Rasmus Villemoesa0512162016-01-20 15:00:13 -0800540 fdh->online_mask = *cpu_online_mask;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000541
Hari Bathini41a65d12019-09-11 20:18:57 +0530542 fw_dump.ops->fadump_trigger(fdh, str);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000543}
544
Hari Bathini7f0ad112019-09-11 20:16:52 +0530545u32 *fadump_regs_to_elf_notes(u32 *buf, struct pt_regs *regs)
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000546{
547 struct elf_prstatus prstatus;
548
549 memset(&prstatus, 0, sizeof(prstatus));
550 /*
551 * FIXME: How do i get PID? Do I really need it?
552 * prstatus.pr_pid = ????
553 */
554 elf_core_copy_kernel_regs(&prstatus.pr_reg, regs);
Hari Bathini22bd0172017-05-08 15:56:24 -0700555 buf = append_elf_note(buf, CRASH_CORE_NOTE_NAME, NT_PRSTATUS,
556 &prstatus, sizeof(prstatus));
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000557 return buf;
558}
559
Hari Bathini7f0ad112019-09-11 20:16:52 +0530560void fadump_update_elfcore_header(char *bufp)
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000561{
562 struct elfhdr *elf;
563 struct elf_phdr *phdr;
564
565 elf = (struct elfhdr *)bufp;
566 bufp += sizeof(struct elfhdr);
567
568 /* First note is a place holder for cpu notes info. */
569 phdr = (struct elf_phdr *)bufp;
570
571 if (phdr->p_type == PT_NOTE) {
Hari Bathini961cf262019-09-11 20:16:36 +0530572 phdr->p_paddr = __pa(fw_dump.cpu_notes_buf_vaddr);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000573 phdr->p_offset = phdr->p_paddr;
574 phdr->p_filesz = fw_dump.cpu_notes_buf_size;
575 phdr->p_memsz = fw_dump.cpu_notes_buf_size;
576 }
577 return;
578}
579
Hari Bathini961cf262019-09-11 20:16:36 +0530580static void *fadump_alloc_buffer(unsigned long size)
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000581{
Hari Bathini72aa6512019-09-11 20:17:56 +0530582 unsigned long count, i;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000583 struct page *page;
Hari Bathini72aa6512019-09-11 20:17:56 +0530584 void *vaddr;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000585
Hari Bathini72aa6512019-09-11 20:17:56 +0530586 vaddr = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000587 if (!vaddr)
588 return NULL;
589
Hari Bathini72aa6512019-09-11 20:17:56 +0530590 count = PAGE_ALIGN(size) / PAGE_SIZE;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000591 page = virt_to_page(vaddr);
592 for (i = 0; i < count; i++)
Hari Bathini72aa6512019-09-11 20:17:56 +0530593 mark_page_reserved(page + i);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000594 return vaddr;
595}
596
Hari Bathini961cf262019-09-11 20:16:36 +0530597static void fadump_free_buffer(unsigned long vaddr, unsigned long size)
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000598{
Hari Bathini72aa6512019-09-11 20:17:56 +0530599 free_reserved_area((void *)vaddr, (void *)(vaddr + size), -1, NULL);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000600}
601
Hari Bathini7f0ad112019-09-11 20:16:52 +0530602s32 fadump_setup_cpu_notes_buf(u32 num_cpus)
Hari Bathini961cf262019-09-11 20:16:36 +0530603{
604 /* Allocate buffer to hold cpu crash notes. */
605 fw_dump.cpu_notes_buf_size = num_cpus * sizeof(note_buf_t);
606 fw_dump.cpu_notes_buf_size = PAGE_ALIGN(fw_dump.cpu_notes_buf_size);
607 fw_dump.cpu_notes_buf_vaddr =
608 (unsigned long)fadump_alloc_buffer(fw_dump.cpu_notes_buf_size);
609 if (!fw_dump.cpu_notes_buf_vaddr) {
610 pr_err("Failed to allocate %ld bytes for CPU notes buffer\n",
611 fw_dump.cpu_notes_buf_size);
612 return -ENOMEM;
613 }
614
615 pr_debug("Allocated buffer for cpu notes of size %ld at 0x%lx\n",
616 fw_dump.cpu_notes_buf_size,
617 fw_dump.cpu_notes_buf_vaddr);
618 return 0;
619}
620
Hari Bathini7f0ad112019-09-11 20:16:52 +0530621void fadump_free_cpu_notes_buf(void)
Hari Bathini961cf262019-09-11 20:16:36 +0530622{
623 if (!fw_dump.cpu_notes_buf_vaddr)
624 return;
625
626 fadump_free_buffer(fw_dump.cpu_notes_buf_vaddr,
627 fw_dump.cpu_notes_buf_size);
628 fw_dump.cpu_notes_buf_vaddr = 0;
629 fw_dump.cpu_notes_buf_size = 0;
630}
631
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530632static void free_crash_memory_ranges(void)
633{
634 kfree(crash_memory_ranges);
635 crash_memory_ranges = NULL;
636 crash_memory_ranges_size = 0;
637 max_crash_mem_ranges = 0;
638}
639
640/*
641 * Allocate or reallocate crash memory ranges array in incremental units
642 * of PAGE_SIZE.
643 */
644static int allocate_crash_memory_ranges(void)
645{
646 struct fad_crash_memory_ranges *new_array;
647 u64 new_size;
648
649 new_size = crash_memory_ranges_size + PAGE_SIZE;
650 pr_debug("Allocating %llu bytes of memory for crash memory ranges\n",
651 new_size);
652
653 new_array = krealloc(crash_memory_ranges, new_size, GFP_KERNEL);
654 if (new_array == NULL) {
655 pr_err("Insufficient memory for setting up crash memory ranges\n");
656 free_crash_memory_ranges();
657 return -ENOMEM;
658 }
659
660 crash_memory_ranges = new_array;
661 crash_memory_ranges_size = new_size;
662 max_crash_mem_ranges = (new_size /
663 sizeof(struct fad_crash_memory_ranges));
664 return 0;
665}
666
667static inline int fadump_add_crash_memory(unsigned long long base,
668 unsigned long long end)
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000669{
Hari Bathiniced1bf52018-08-07 02:12:54 +0530670 u64 start, size;
671 bool is_adjacent = false;
672
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000673 if (base == end)
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530674 return 0;
675
Hari Bathiniced1bf52018-08-07 02:12:54 +0530676 /*
677 * Fold adjacent memory ranges to bring down the memory ranges/
678 * PT_LOAD segments count.
679 */
680 if (crash_mem_ranges) {
681 start = crash_memory_ranges[crash_mem_ranges - 1].base;
682 size = crash_memory_ranges[crash_mem_ranges - 1].size;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530683
Hari Bathiniced1bf52018-08-07 02:12:54 +0530684 if ((start + size) == base)
685 is_adjacent = true;
686 }
687 if (!is_adjacent) {
688 /* resize the array on reaching the limit */
689 if (crash_mem_ranges == max_crash_mem_ranges) {
690 int ret;
691
692 ret = allocate_crash_memory_ranges();
693 if (ret)
694 return ret;
695 }
696
697 start = base;
698 crash_memory_ranges[crash_mem_ranges].base = start;
699 crash_mem_ranges++;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530700 }
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000701
Hari Bathiniced1bf52018-08-07 02:12:54 +0530702 crash_memory_ranges[crash_mem_ranges - 1].size = (end - start);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000703 pr_debug("crash_memory_range[%d] [%#016llx-%#016llx], %#llx bytes\n",
Hari Bathiniced1bf52018-08-07 02:12:54 +0530704 (crash_mem_ranges - 1), start, end - 1, (end - start));
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530705 return 0;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000706}
707
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530708static int fadump_exclude_reserved_area(unsigned long long start,
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000709 unsigned long long end)
710{
711 unsigned long long ra_start, ra_end;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530712 int ret = 0;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000713
714 ra_start = fw_dump.reserve_dump_area_start;
715 ra_end = ra_start + fw_dump.reserve_dump_area_size;
716
717 if ((ra_start < end) && (ra_end > start)) {
718 if ((start < ra_start) && (end > ra_end)) {
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530719 ret = fadump_add_crash_memory(start, ra_start);
720 if (ret)
721 return ret;
722
723 ret = fadump_add_crash_memory(ra_end, end);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000724 } else if (start < ra_start) {
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530725 ret = fadump_add_crash_memory(start, ra_start);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000726 } else if (ra_end < end) {
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530727 ret = fadump_add_crash_memory(ra_end, end);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000728 }
729 } else
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530730 ret = fadump_add_crash_memory(start, end);
731
732 return ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000733}
734
735static int fadump_init_elfcore_header(char *bufp)
736{
737 struct elfhdr *elf;
738
739 elf = (struct elfhdr *) bufp;
740 bufp += sizeof(struct elfhdr);
741 memcpy(elf->e_ident, ELFMAG, SELFMAG);
742 elf->e_ident[EI_CLASS] = ELF_CLASS;
743 elf->e_ident[EI_DATA] = ELF_DATA;
744 elf->e_ident[EI_VERSION] = EV_CURRENT;
745 elf->e_ident[EI_OSABI] = ELF_OSABI;
746 memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
747 elf->e_type = ET_CORE;
748 elf->e_machine = ELF_ARCH;
749 elf->e_version = EV_CURRENT;
750 elf->e_entry = 0;
751 elf->e_phoff = sizeof(struct elfhdr);
752 elf->e_shoff = 0;
Daniel Axtensd8bced22016-09-06 15:32:42 +1000753#if defined(_CALL_ELF)
754 elf->e_flags = _CALL_ELF;
755#else
756 elf->e_flags = 0;
757#endif
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000758 elf->e_ehsize = sizeof(struct elfhdr);
759 elf->e_phentsize = sizeof(struct elf_phdr);
760 elf->e_phnum = 0;
761 elf->e_shentsize = 0;
762 elf->e_shnum = 0;
763 elf->e_shstrndx = 0;
764
765 return 0;
766}
767
768/*
769 * Traverse through memblock structure and setup crash memory ranges. These
770 * ranges will be used create PT_LOAD program headers in elfcore header.
771 */
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530772static int fadump_setup_crash_memory_ranges(void)
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000773{
774 struct memblock_region *reg;
775 unsigned long long start, end;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530776 int ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000777
778 pr_debug("Setup crash memory ranges.\n");
779 crash_mem_ranges = 0;
Hari Bathiniced1bf52018-08-07 02:12:54 +0530780
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000781 /*
782 * add the first memory chunk (RMA_START through boot_memory_size) as
783 * a separate memory chunk. The reason is, at the time crash firmware
784 * will move the content of this memory chunk to different location
785 * specified during fadump registration. We need to create a separate
786 * program header for this chunk with the correct offset.
787 */
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530788 ret = fadump_add_crash_memory(RMA_START, fw_dump.boot_memory_size);
789 if (ret)
790 return ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000791
792 for_each_memblock(memory, reg) {
793 start = (unsigned long long)reg->base;
794 end = start + (unsigned long long)reg->size;
Hari Bathinia77af5522017-06-01 22:50:38 +0530795
796 /*
797 * skip the first memory chunk that is already added (RMA_START
798 * through boot_memory_size). This logic needs a relook if and
799 * when RMA_START changes to a non-zero value.
800 */
801 BUILD_BUG_ON(RMA_START != 0);
802 if (start < fw_dump.boot_memory_size) {
803 if (end > fw_dump.boot_memory_size)
804 start = fw_dump.boot_memory_size;
805 else
806 continue;
807 }
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000808
809 /* add this range excluding the reserved dump area. */
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530810 ret = fadump_exclude_reserved_area(start, end);
811 if (ret)
812 return ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000813 }
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530814
815 return 0;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000816}
817
Mahesh Salgaonkard34c5f22012-02-16 01:14:53 +0000818/*
819 * If the given physical address falls within the boot memory region then
820 * return the relocated address that points to the dump region reserved
821 * for saving initial boot memory contents.
822 */
823static inline unsigned long fadump_relocate(unsigned long paddr)
824{
825 if (paddr > RMA_START && paddr < fw_dump.boot_memory_size)
Hari Bathini41a65d12019-09-11 20:18:57 +0530826 return fw_dump.boot_mem_dest_addr + paddr;
Mahesh Salgaonkard34c5f22012-02-16 01:14:53 +0000827 else
828 return paddr;
829}
830
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000831static int fadump_create_elfcore_headers(char *bufp)
832{
833 struct elfhdr *elf;
834 struct elf_phdr *phdr;
835 int i;
836
837 fadump_init_elfcore_header(bufp);
838 elf = (struct elfhdr *)bufp;
839 bufp += sizeof(struct elfhdr);
840
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000841 /*
842 * setup ELF PT_NOTE, place holder for cpu notes info. The notes info
843 * will be populated during second kernel boot after crash. Hence
844 * this PT_NOTE will always be the first elf note.
845 *
846 * NOTE: Any new ELF note addition should be placed after this note.
847 */
848 phdr = (struct elf_phdr *)bufp;
849 bufp += sizeof(struct elf_phdr);
850 phdr->p_type = PT_NOTE;
851 phdr->p_flags = 0;
852 phdr->p_vaddr = 0;
853 phdr->p_align = 0;
854
855 phdr->p_offset = 0;
856 phdr->p_paddr = 0;
857 phdr->p_filesz = 0;
858 phdr->p_memsz = 0;
859
860 (elf->e_phnum)++;
861
Mahesh Salgaonkard34c5f22012-02-16 01:14:53 +0000862 /* setup ELF PT_NOTE for vmcoreinfo */
863 phdr = (struct elf_phdr *)bufp;
864 bufp += sizeof(struct elf_phdr);
865 phdr->p_type = PT_NOTE;
866 phdr->p_flags = 0;
867 phdr->p_vaddr = 0;
868 phdr->p_align = 0;
869
870 phdr->p_paddr = fadump_relocate(paddr_vmcoreinfo_note());
871 phdr->p_offset = phdr->p_paddr;
Xunlei Pang5203f492017-07-12 14:33:17 -0700872 phdr->p_memsz = phdr->p_filesz = VMCOREINFO_NOTE_SIZE;
Mahesh Salgaonkard34c5f22012-02-16 01:14:53 +0000873
874 /* Increment number of program headers. */
875 (elf->e_phnum)++;
876
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000877 /* setup PT_LOAD sections. */
878
879 for (i = 0; i < crash_mem_ranges; i++) {
880 unsigned long long mbase, msize;
881 mbase = crash_memory_ranges[i].base;
882 msize = crash_memory_ranges[i].size;
883
884 if (!msize)
885 continue;
886
887 phdr = (struct elf_phdr *)bufp;
888 bufp += sizeof(struct elf_phdr);
889 phdr->p_type = PT_LOAD;
890 phdr->p_flags = PF_R|PF_W|PF_X;
891 phdr->p_offset = mbase;
892
893 if (mbase == RMA_START) {
894 /*
895 * The entire RMA region will be moved by firmware
896 * to the specified destination_address. Hence set
897 * the correct offset.
898 */
Hari Bathini41a65d12019-09-11 20:18:57 +0530899 phdr->p_offset = fw_dump.boot_mem_dest_addr;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000900 }
901
902 phdr->p_paddr = mbase;
903 phdr->p_vaddr = (unsigned long)__va(mbase);
904 phdr->p_filesz = msize;
905 phdr->p_memsz = msize;
906 phdr->p_align = 0;
907
908 /* Increment number of program headers. */
909 (elf->e_phnum)++;
910 }
911 return 0;
912}
913
914static unsigned long init_fadump_header(unsigned long addr)
915{
916 struct fadump_crash_info_header *fdh;
917
918 if (!addr)
919 return 0;
920
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000921 fdh = __va(addr);
922 addr += sizeof(struct fadump_crash_info_header);
923
924 memset(fdh, 0, sizeof(struct fadump_crash_info_header));
925 fdh->magic_number = FADUMP_CRASH_INFO_MAGIC;
926 fdh->elfcorehdr_addr = addr;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000927 /* We will set the crashing cpu id in crash_fadump() during crash. */
Hari Bathini0226e552019-09-11 20:18:14 +0530928 fdh->crashing_cpu = FADUMP_CPU_UNKNOWN;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000929
930 return addr;
931}
932
Michal Suchanek98b8cd72017-05-27 17:46:15 +0200933static int register_fadump(void)
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000934{
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000935 unsigned long addr;
936 void *vaddr;
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530937 int ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000938
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000939 /*
940 * If no memory is reserved then we can not register for firmware-
941 * assisted dump.
942 */
943 if (!fw_dump.reserve_dump_area_size)
Michal Suchanek98b8cd72017-05-27 17:46:15 +0200944 return -ENODEV;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000945
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530946 ret = fadump_setup_crash_memory_ranges();
947 if (ret)
948 return ret;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000949
Hari Bathini41a65d12019-09-11 20:18:57 +0530950 addr = fw_dump.fadumphdr_addr;
951
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000952 /* Initialize fadump crash info header. */
953 addr = init_fadump_header(addr);
954 vaddr = __va(addr);
955
956 pr_debug("Creating ELF core headers at %#016lx\n", addr);
957 fadump_create_elfcore_headers(vaddr);
958
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000959 /* register the future kernel dump with firmware. */
Hari Bathini41a65d12019-09-11 20:18:57 +0530960 pr_debug("Registering for firmware-assisted kernel dump...\n");
961 return fw_dump.ops->fadump_register(&fw_dump);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000962}
963
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +0000964void fadump_cleanup(void)
965{
Hari Bathini2790d012019-09-11 20:21:16 +0530966 if (!fw_dump.fadump_supported)
967 return;
968
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +0000969 /* Invalidate the registration only if dump is active. */
970 if (fw_dump.dump_active) {
Hari Bathinif3512012019-09-11 20:19:44 +0530971 pr_debug("Invalidating firmware-assisted dump registration\n");
972 fw_dump.ops->fadump_invalidate(&fw_dump);
Mahesh Salgaonkar722cde72018-04-27 11:53:18 +0530973 } else if (fw_dump.dump_registered) {
974 /* Un-register Firmware-assisted dump if it was registered. */
Hari Bathini41a65d12019-09-11 20:18:57 +0530975 fw_dump.ops->fadump_unregister(&fw_dump);
Hari Bathini1bd6a1c2018-08-07 02:12:45 +0530976 free_crash_memory_ranges();
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +0000977 }
Hari Bathini2790d012019-09-11 20:21:16 +0530978
979 if (fw_dump.ops->fadump_cleanup)
980 fw_dump.ops->fadump_cleanup(&fw_dump);
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +0000981}
982
Hari Bathini68fa6472017-06-02 01:10:10 +0530983static void fadump_free_reserved_memory(unsigned long start_pfn,
984 unsigned long end_pfn)
985{
986 unsigned long pfn;
987 unsigned long time_limit = jiffies + HZ;
988
989 pr_info("freeing reserved memory (0x%llx - 0x%llx)\n",
990 PFN_PHYS(start_pfn), PFN_PHYS(end_pfn));
991
992 for (pfn = start_pfn; pfn < end_pfn; pfn++) {
993 free_reserved_page(pfn_to_page(pfn));
994
995 if (time_after(jiffies, time_limit)) {
996 cond_resched();
997 time_limit = jiffies + HZ;
998 }
999 }
1000}
1001
1002/*
1003 * Skip memory holes and free memory that was actually reserved.
1004 */
1005static void fadump_release_reserved_area(unsigned long start, unsigned long end)
1006{
1007 struct memblock_region *reg;
1008 unsigned long tstart, tend;
1009 unsigned long start_pfn = PHYS_PFN(start);
1010 unsigned long end_pfn = PHYS_PFN(end);
1011
1012 for_each_memblock(memory, reg) {
1013 tstart = max(start_pfn, memblock_region_memory_base_pfn(reg));
1014 tend = min(end_pfn, memblock_region_memory_end_pfn(reg));
1015 if (tstart < tend) {
1016 fadump_free_reserved_memory(tstart, tend);
1017
1018 if (tend == end_pfn)
1019 break;
1020
1021 start_pfn = tend + 1;
1022 }
1023 }
1024}
1025
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001026/*
1027 * Release the memory that was reserved in early boot to preserve the memory
1028 * contents. The released memory will be available for general use.
1029 */
1030static void fadump_release_memory(unsigned long begin, unsigned long end)
1031{
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001032 unsigned long ra_start, ra_end;
1033
1034 ra_start = fw_dump.reserve_dump_area_start;
1035 ra_end = ra_start + fw_dump.reserve_dump_area_size;
1036
Hari Bathini68fa6472017-06-02 01:10:10 +05301037 /*
1038 * exclude the dump reserve area. Will reuse it for next
1039 * fadump registration.
1040 */
1041 if (begin < ra_end && end > ra_start) {
1042 if (begin < ra_start)
1043 fadump_release_reserved_area(begin, ra_start);
1044 if (end > ra_end)
1045 fadump_release_reserved_area(ra_end, end);
1046 } else
1047 fadump_release_reserved_area(begin, end);
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001048}
1049
1050static void fadump_invalidate_release_mem(void)
1051{
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001052 mutex_lock(&fadump_mutex);
1053 if (!fw_dump.dump_active) {
1054 mutex_unlock(&fadump_mutex);
1055 return;
1056 }
1057
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001058 fadump_cleanup();
1059 mutex_unlock(&fadump_mutex);
1060
Hari Bathini8255da92019-09-11 20:19:28 +05301061 fadump_release_memory(fw_dump.boot_memory_size, memblock_end_of_DRAM());
Hari Bathini961cf262019-09-11 20:16:36 +05301062 fadump_free_cpu_notes_buf();
1063
Hari Bathinia4e2e2c2019-09-11 20:23:28 +05301064 /*
1065 * Setup kernel metadata and initialize the kernel dump
1066 * memory structure for FADump re-registration.
1067 */
1068 if (fw_dump.ops->fadump_setup_metadata &&
1069 (fw_dump.ops->fadump_setup_metadata(&fw_dump) < 0))
1070 pr_warn("Failed to setup kernel metadata!\n");
Hari Bathini41a65d12019-09-11 20:18:57 +05301071 fw_dump.ops->fadump_init_mem_struct(&fw_dump);
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001072}
1073
1074static ssize_t fadump_release_memory_store(struct kobject *kobj,
1075 struct kobj_attribute *attr,
1076 const char *buf, size_t count)
1077{
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001078 int input = -1;
1079
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001080 if (!fw_dump.dump_active)
1081 return -EPERM;
1082
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001083 if (kstrtoint(buf, 0, &input))
1084 return -EINVAL;
1085
1086 if (input == 1) {
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001087 /*
1088 * Take away the '/proc/vmcore'. We are releasing the dump
1089 * memory, hence it will not be valid anymore.
1090 */
Michael Ellerman2685f822016-09-30 10:51:46 +10001091#ifdef CONFIG_PROC_VMCORE
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001092 vmcore_cleanup();
Michael Ellerman2685f822016-09-30 10:51:46 +10001093#endif
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001094 fadump_invalidate_release_mem();
1095
1096 } else
1097 return -EINVAL;
1098 return count;
1099}
1100
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001101static ssize_t fadump_enabled_show(struct kobject *kobj,
1102 struct kobj_attribute *attr,
1103 char *buf)
1104{
1105 return sprintf(buf, "%d\n", fw_dump.fadump_enabled);
1106}
1107
1108static ssize_t fadump_register_show(struct kobject *kobj,
1109 struct kobj_attribute *attr,
1110 char *buf)
1111{
1112 return sprintf(buf, "%d\n", fw_dump.dump_registered);
1113}
1114
1115static ssize_t fadump_register_store(struct kobject *kobj,
1116 struct kobj_attribute *attr,
1117 const char *buf, size_t count)
1118{
1119 int ret = 0;
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001120 int input = -1;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001121
Hari Bathinif3512012019-09-11 20:19:44 +05301122 if (!fw_dump.fadump_enabled || fw_dump.dump_active)
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001123 return -EPERM;
1124
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001125 if (kstrtoint(buf, 0, &input))
1126 return -EINVAL;
1127
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001128 mutex_lock(&fadump_mutex);
1129
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001130 switch (input) {
1131 case 0:
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001132 if (fw_dump.dump_registered == 0) {
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001133 goto unlock_out;
1134 }
Hari Bathinif3512012019-09-11 20:19:44 +05301135
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001136 /* Un-register Firmware-assisted dump */
Hari Bathini41a65d12019-09-11 20:18:57 +05301137 pr_debug("Un-register firmware-assisted dump\n");
1138 fw_dump.ops->fadump_unregister(&fw_dump);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001139 break;
Michal Suchanekdcdc4672017-06-26 16:06:01 +02001140 case 1:
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001141 if (fw_dump.dump_registered == 1) {
Hari Bathini0823c682018-09-14 19:36:02 +05301142 /* Un-register Firmware-assisted dump */
Hari Bathini41a65d12019-09-11 20:18:57 +05301143 fw_dump.ops->fadump_unregister(&fw_dump);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001144 }
1145 /* Register Firmware-assisted dump */
Michal Suchanek98b8cd72017-05-27 17:46:15 +02001146 ret = register_fadump();
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001147 break;
1148 default:
1149 ret = -EINVAL;
1150 break;
1151 }
1152
1153unlock_out:
1154 mutex_unlock(&fadump_mutex);
1155 return ret < 0 ? ret : count;
1156}
1157
1158static int fadump_region_show(struct seq_file *m, void *private)
1159{
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001160 if (!fw_dump.fadump_enabled)
1161 return 0;
1162
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001163 mutex_lock(&fadump_mutex);
Hari Bathinif3512012019-09-11 20:19:44 +05301164 fw_dump.ops->fadump_region_show(&fw_dump, m);
1165 mutex_unlock(&fadump_mutex);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001166 return 0;
1167}
1168
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001169static struct kobj_attribute fadump_release_attr = __ATTR(fadump_release_mem,
1170 0200, NULL,
1171 fadump_release_memory_store);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001172static struct kobj_attribute fadump_attr = __ATTR(fadump_enabled,
1173 0444, fadump_enabled_show,
1174 NULL);
1175static struct kobj_attribute fadump_register_attr = __ATTR(fadump_registered,
1176 0644, fadump_register_show,
1177 fadump_register_store);
1178
Yangtao Lif6cee262018-11-05 10:01:19 -05001179DEFINE_SHOW_ATTRIBUTE(fadump_region);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001180
1181static void fadump_init_files(void)
1182{
1183 struct dentry *debugfs_file;
1184 int rc = 0;
1185
1186 rc = sysfs_create_file(kernel_kobj, &fadump_attr.attr);
1187 if (rc)
1188 printk(KERN_ERR "fadump: unable to create sysfs file"
1189 " fadump_enabled (%d)\n", rc);
1190
1191 rc = sysfs_create_file(kernel_kobj, &fadump_register_attr.attr);
1192 if (rc)
1193 printk(KERN_ERR "fadump: unable to create sysfs file"
1194 " fadump_registered (%d)\n", rc);
1195
1196 debugfs_file = debugfs_create_file("fadump_region", 0444,
1197 powerpc_debugfs_root, NULL,
1198 &fadump_region_fops);
1199 if (!debugfs_file)
1200 printk(KERN_ERR "fadump: unable to create debugfs file"
1201 " fadump_region\n");
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001202
1203 if (fw_dump.dump_active) {
1204 rc = sysfs_create_file(kernel_kobj, &fadump_release_attr.attr);
1205 if (rc)
1206 printk(KERN_ERR "fadump: unable to create sysfs file"
1207 " fadump_release_mem (%d)\n", rc);
1208 }
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001209 return;
1210}
1211
1212/*
1213 * Prepare for firmware-assisted dump.
1214 */
1215int __init setup_fadump(void)
1216{
1217 if (!fw_dump.fadump_enabled)
1218 return 0;
1219
1220 if (!fw_dump.fadump_supported) {
1221 printk(KERN_ERR "Firmware-assisted dump is not supported on"
1222 " this hardware\n");
1223 return 0;
1224 }
1225
1226 fadump_show_config();
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +00001227 /*
1228 * If dump data is available then see if it is valid and prepare for
1229 * saving it to the disk.
1230 */
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001231 if (fw_dump.dump_active) {
1232 /*
1233 * if dump process fails then invalidate the registration
1234 * and release memory before proceeding for re-registration.
1235 */
Hari Bathinif3512012019-09-11 20:19:44 +05301236 if (fw_dump.ops->fadump_process(&fw_dump) < 0)
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001237 fadump_invalidate_release_mem();
1238 }
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001239 /* Initialize the kernel dump memory structure for FAD registration. */
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +00001240 else if (fw_dump.reserve_dump_area_size)
Hari Bathini41a65d12019-09-11 20:18:57 +05301241 fw_dump.ops->fadump_init_mem_struct(&fw_dump);
Hari Bathinif3512012019-09-11 20:19:44 +05301242
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001243 fadump_init_files();
1244
1245 return 1;
1246}
1247subsys_initcall(setup_fadump);