blob: 1bdbe0b257e04df024327ec281c6efd7c5c119a9 [file] [log] [blame]
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +00001/*
2 * Firmware Assisted dump: A robust mechanism to get reliable kernel crash
3 * dump with assistance from firmware. This approach does not use kexec,
4 * instead firmware assists in booting the kdump kernel while preserving
5 * memory contents. The most of the code implementation has been adapted
6 * from phyp assisted dump implementation written by Linas Vepstas and
7 * Manish Ahuja
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 *
23 * Copyright 2011 IBM Corporation
24 * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
25 */
26
27#undef DEBUG
28#define pr_fmt(fmt) "fadump: " fmt
29
30#include <linux/string.h>
31#include <linux/memblock.h>
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +000032#include <linux/delay.h>
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +000033#include <linux/seq_file.h>
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +000034#include <linux/crash_dump.h>
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +000035#include <linux/kobject.h>
36#include <linux/sysfs.h>
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000037
Michael Ellerman7644d582017-02-10 12:04:56 +110038#include <asm/debugfs.h>
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000039#include <asm/page.h>
40#include <asm/prom.h>
41#include <asm/rtas.h>
42#include <asm/fadump.h>
Stephen Rothwellcad3c832012-03-30 14:01:07 +000043#include <asm/setup.h>
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000044
45static struct fw_dump fw_dump;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +000046static struct fadump_mem_struct fdm;
47static const struct fadump_mem_struct *fdm_active;
48
49static DEFINE_MUTEX(fadump_mutex);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +000050struct fad_crash_memory_ranges crash_memory_ranges[INIT_CRASHMEM_RANGES];
51int crash_mem_ranges;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000052
53/* Scan the Firmware Assisted dump configuration details. */
54int __init early_init_dt_scan_fw_dump(unsigned long node,
55 const char *uname, int depth, void *data)
56{
Rob Herring9d0c4df2014-04-01 23:49:03 -050057 const __be32 *sections;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000058 int i, num_sections;
Rob Herring9d0c4df2014-04-01 23:49:03 -050059 int size;
Hari Bathini408cddd2014-10-01 12:32:30 +053060 const __be32 *token;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000061
62 if (depth != 1 || strcmp(uname, "rtas") != 0)
63 return 0;
64
65 /*
66 * Check if Firmware Assisted dump is supported. if yes, check
67 * if dump has been initiated on last reboot.
68 */
69 token = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL);
70 if (!token)
Gavin Shana7d043172014-04-24 18:00:31 +100071 return 1;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000072
73 fw_dump.fadump_supported = 1;
Hari Bathini408cddd2014-10-01 12:32:30 +053074 fw_dump.ibm_configure_kernel_dump = be32_to_cpu(*token);
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000075
76 /*
77 * The 'ibm,kernel-dump' rtas node is present only if there is
78 * dump data waiting for us.
79 */
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +000080 fdm_active = of_get_flat_dt_prop(node, "ibm,kernel-dump", NULL);
81 if (fdm_active)
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000082 fw_dump.dump_active = 1;
83
84 /* Get the sizes required to store dump data for the firmware provided
85 * dump sections.
86 * For each dump section type supported, a 32bit cell which defines
87 * the ID of a supported section followed by two 32 bit cells which
88 * gives teh size of the section in bytes.
89 */
90 sections = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes",
91 &size);
92
93 if (!sections)
Gavin Shana7d043172014-04-24 18:00:31 +100094 return 1;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +000095
96 num_sections = size / (3 * sizeof(u32));
97
98 for (i = 0; i < num_sections; i++, sections += 3) {
99 u32 type = (u32)of_read_number(sections, 1);
100
101 switch (type) {
102 case FADUMP_CPU_STATE_DATA:
103 fw_dump.cpu_state_data_size =
104 of_read_ulong(&sections[1], 2);
105 break;
106 case FADUMP_HPTE_REGION:
107 fw_dump.hpte_region_size =
108 of_read_ulong(&sections[1], 2);
109 break;
110 }
111 }
Gavin Shana7d043172014-04-24 18:00:31 +1000112
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000113 return 1;
114}
115
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000116int is_fadump_active(void)
117{
118 return fw_dump.dump_active;
119}
120
121/* Print firmware assisted dump configurations for debugging purpose. */
122static void fadump_show_config(void)
123{
124 pr_debug("Support for firmware-assisted dump (fadump): %s\n",
125 (fw_dump.fadump_supported ? "present" : "no support"));
126
127 if (!fw_dump.fadump_supported)
128 return;
129
130 pr_debug("Fadump enabled : %s\n",
131 (fw_dump.fadump_enabled ? "yes" : "no"));
132 pr_debug("Dump Active : %s\n",
133 (fw_dump.dump_active ? "yes" : "no"));
134 pr_debug("Dump section sizes:\n");
135 pr_debug(" CPU state data size: %lx\n", fw_dump.cpu_state_data_size);
136 pr_debug(" HPTE region size : %lx\n", fw_dump.hpte_region_size);
137 pr_debug("Boot memory size : %lx\n", fw_dump.boot_memory_size);
138}
139
140static unsigned long init_fadump_mem_struct(struct fadump_mem_struct *fdm,
141 unsigned long addr)
142{
143 if (!fdm)
144 return 0;
145
146 memset(fdm, 0, sizeof(struct fadump_mem_struct));
147 addr = addr & PAGE_MASK;
148
Hari Bathini408cddd2014-10-01 12:32:30 +0530149 fdm->header.dump_format_version = cpu_to_be32(0x00000001);
150 fdm->header.dump_num_sections = cpu_to_be16(3);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000151 fdm->header.dump_status_flag = 0;
152 fdm->header.offset_first_dump_section =
Hari Bathini408cddd2014-10-01 12:32:30 +0530153 cpu_to_be32((u32)offsetof(struct fadump_mem_struct, cpu_state_data));
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000154
155 /*
156 * Fields for disk dump option.
157 * We are not using disk dump option, hence set these fields to 0.
158 */
159 fdm->header.dd_block_size = 0;
160 fdm->header.dd_block_offset = 0;
161 fdm->header.dd_num_blocks = 0;
162 fdm->header.dd_offset_disk_path = 0;
163
164 /* set 0 to disable an automatic dump-reboot. */
165 fdm->header.max_time_auto = 0;
166
167 /* Kernel dump sections */
168 /* cpu state data section. */
Hari Bathini408cddd2014-10-01 12:32:30 +0530169 fdm->cpu_state_data.request_flag = cpu_to_be32(FADUMP_REQUEST_FLAG);
170 fdm->cpu_state_data.source_data_type = cpu_to_be16(FADUMP_CPU_STATE_DATA);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000171 fdm->cpu_state_data.source_address = 0;
Hari Bathini408cddd2014-10-01 12:32:30 +0530172 fdm->cpu_state_data.source_len = cpu_to_be64(fw_dump.cpu_state_data_size);
173 fdm->cpu_state_data.destination_address = cpu_to_be64(addr);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000174 addr += fw_dump.cpu_state_data_size;
175
176 /* hpte region section */
Hari Bathini408cddd2014-10-01 12:32:30 +0530177 fdm->hpte_region.request_flag = cpu_to_be32(FADUMP_REQUEST_FLAG);
178 fdm->hpte_region.source_data_type = cpu_to_be16(FADUMP_HPTE_REGION);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000179 fdm->hpte_region.source_address = 0;
Hari Bathini408cddd2014-10-01 12:32:30 +0530180 fdm->hpte_region.source_len = cpu_to_be64(fw_dump.hpte_region_size);
181 fdm->hpte_region.destination_address = cpu_to_be64(addr);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000182 addr += fw_dump.hpte_region_size;
183
184 /* RMA region section */
Hari Bathini408cddd2014-10-01 12:32:30 +0530185 fdm->rmr_region.request_flag = cpu_to_be32(FADUMP_REQUEST_FLAG);
186 fdm->rmr_region.source_data_type = cpu_to_be16(FADUMP_REAL_MODE_REGION);
187 fdm->rmr_region.source_address = cpu_to_be64(RMA_START);
188 fdm->rmr_region.source_len = cpu_to_be64(fw_dump.boot_memory_size);
189 fdm->rmr_region.destination_address = cpu_to_be64(addr);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000190 addr += fw_dump.boot_memory_size;
191
192 return addr;
193}
194
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000195/**
196 * fadump_calculate_reserve_size(): reserve variable boot area 5% of System RAM
197 *
198 * Function to find the largest memory size we need to reserve during early
199 * boot process. This will be the size of the memory that is required for a
200 * kernel to boot successfully.
201 *
202 * This function has been taken from phyp-assisted dump feature implementation.
203 *
204 * returns larger of 256MB or 5% rounded down to multiples of 256MB.
205 *
206 * TODO: Come up with better approach to find out more accurate memory size
207 * that is required for a kernel to boot successfully.
208 *
209 */
210static inline unsigned long fadump_calculate_reserve_size(void)
211{
Hari Bathini11550dc2017-05-08 15:56:28 -0700212 int ret;
213 unsigned long long base, size;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000214
Hari Bathini81d9eca2017-05-22 15:04:23 +0530215 if (fw_dump.reserve_bootvar)
216 pr_warn("'fadump_reserve_mem=' parameter is deprecated in favor of 'crashkernel=' parameter.\n");
217
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000218 /*
Hari Bathini11550dc2017-05-08 15:56:28 -0700219 * Check if the size is specified through crashkernel= cmdline
220 * option. If yes, then use that but ignore base as fadump
221 * reserves memory at end of RAM.
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000222 */
Hari Bathini11550dc2017-05-08 15:56:28 -0700223 ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
224 &size, &base);
225 if (ret == 0 && size > 0) {
Hari Bathini81d9eca2017-05-22 15:04:23 +0530226 if (fw_dump.reserve_bootvar)
227 pr_info("Using 'crashkernel=' parameter for memory reservation.\n");
228
Hari Bathini11550dc2017-05-08 15:56:28 -0700229 fw_dump.reserve_bootvar = (unsigned long)size;
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000230 return fw_dump.reserve_bootvar;
Hari Bathini81d9eca2017-05-22 15:04:23 +0530231 } else if (fw_dump.reserve_bootvar) {
232 /*
233 * 'fadump_reserve_mem=' is being used to reserve memory
234 * for firmware-assisted dump.
235 */
236 return fw_dump.reserve_bootvar;
Hari Bathini11550dc2017-05-08 15:56:28 -0700237 }
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000238
239 /* divide by 20 to get 5% of value */
240 size = memblock_end_of_DRAM() / 20;
241
242 /* round it down in multiples of 256 */
243 size = size & ~0x0FFFFFFFUL;
244
245 /* Truncate to memory_limit. We don't want to over reserve the memory.*/
246 if (memory_limit && size > memory_limit)
247 size = memory_limit;
248
249 return (size > MIN_BOOT_MEM ? size : MIN_BOOT_MEM);
250}
251
252/*
253 * Calculate the total memory size required to be reserved for
254 * firmware-assisted dump registration.
255 */
256static unsigned long get_fadump_area_size(void)
257{
258 unsigned long size = 0;
259
260 size += fw_dump.cpu_state_data_size;
261 size += fw_dump.hpte_region_size;
262 size += fw_dump.boot_memory_size;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000263 size += sizeof(struct fadump_crash_info_header);
264 size += sizeof(struct elfhdr); /* ELF core header.*/
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000265 size += sizeof(struct elf_phdr); /* place holder for cpu notes */
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000266 /* Program headers for crash memory regions. */
267 size += sizeof(struct elf_phdr) * (memblock_num_regions(memory) + 2);
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000268
269 size = PAGE_ALIGN(size);
270 return size;
271}
272
273int __init fadump_reserve_mem(void)
274{
275 unsigned long base, size, memory_boundary;
276
277 if (!fw_dump.fadump_enabled)
278 return 0;
279
280 if (!fw_dump.fadump_supported) {
281 printk(KERN_INFO "Firmware-assisted dump is not supported on"
282 " this hardware\n");
283 fw_dump.fadump_enabled = 0;
284 return 0;
285 }
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000286 /*
287 * Initialize boot memory size
288 * If dump is active then we have already calculated the size during
289 * first kernel.
290 */
291 if (fdm_active)
Hari Bathini408cddd2014-10-01 12:32:30 +0530292 fw_dump.boot_memory_size = be64_to_cpu(fdm_active->rmr_region.source_len);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000293 else
294 fw_dump.boot_memory_size = fadump_calculate_reserve_size();
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000295
296 /*
297 * Calculate the memory boundary.
298 * If memory_limit is less than actual memory boundary then reserve
299 * the memory for fadump beyond the memory_limit and adjust the
300 * memory_limit accordingly, so that the running kernel can run with
301 * specified memory_limit.
302 */
303 if (memory_limit && memory_limit < memblock_end_of_DRAM()) {
304 size = get_fadump_area_size();
305 if ((memory_limit + size) < memblock_end_of_DRAM())
306 memory_limit += size;
307 else
308 memory_limit = memblock_end_of_DRAM();
309 printk(KERN_INFO "Adjusted memory_limit for firmware-assisted"
Suzuki Poulosea84fcd42012-08-21 01:42:33 +0000310 " dump, now %#016llx\n", memory_limit);
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000311 }
312 if (memory_limit)
313 memory_boundary = memory_limit;
314 else
315 memory_boundary = memblock_end_of_DRAM();
316
317 if (fw_dump.dump_active) {
318 printk(KERN_INFO "Firmware-assisted dump is active.\n");
319 /*
320 * If last boot has crashed then reserve all the memory
321 * above boot_memory_size so that we don't touch it until
322 * dump is written to disk by userspace tool. This memory
323 * will be released for general use once the dump is saved.
324 */
325 base = fw_dump.boot_memory_size;
326 size = memory_boundary - base;
327 memblock_reserve(base, size);
328 printk(KERN_INFO "Reserved %ldMB of memory at %ldMB "
329 "for saving crash dump\n",
330 (unsigned long)(size >> 20),
331 (unsigned long)(base >> 20));
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000332
333 fw_dump.fadumphdr_addr =
Hari Bathini408cddd2014-10-01 12:32:30 +0530334 be64_to_cpu(fdm_active->rmr_region.destination_address) +
335 be64_to_cpu(fdm_active->rmr_region.source_len);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000336 pr_debug("fadumphdr_addr = %p\n",
337 (void *) fw_dump.fadumphdr_addr);
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000338 } else {
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000339 size = get_fadump_area_size();
Hari Bathinif6e6bed2017-03-17 02:35:26 +0530340
341 /*
342 * Reserve memory at an offset closer to bottom of the RAM to
343 * minimize the impact of memory hot-remove operation. We can't
344 * use memblock_find_in_range() here since it doesn't allocate
345 * from bottom to top.
346 */
347 for (base = fw_dump.boot_memory_size;
348 base <= (memory_boundary - size);
349 base += size) {
350 if (memblock_is_region_memory(base, size) &&
351 !memblock_is_region_reserved(base, size))
352 break;
353 }
354 if ((base > (memory_boundary - size)) ||
355 memblock_reserve(base, size)) {
356 pr_err("Failed to reserve memory\n");
357 return 0;
358 }
359
360 pr_info("Reserved %ldMB of memory at %ldMB for firmware-"
361 "assisted dump (System RAM: %ldMB)\n",
362 (unsigned long)(size >> 20),
363 (unsigned long)(base >> 20),
364 (unsigned long)(memblock_phys_mem_size() >> 20));
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000365 }
Hari Bathinif6e6bed2017-03-17 02:35:26 +0530366
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000367 fw_dump.reserve_dump_area_start = base;
368 fw_dump.reserve_dump_area_size = size;
369 return 1;
370}
371
Srikar Dronamraju1e76609c2016-10-07 16:59:21 -0700372unsigned long __init arch_reserved_kernel_pages(void)
373{
374 return memblock_reserved_size() / PAGE_SIZE;
375}
376
Mahesh Salgaonkareb39c882012-02-16 01:14:22 +0000377/* Look for fadump= cmdline option. */
378static int __init early_fadump_param(char *p)
379{
380 if (!p)
381 return 1;
382
383 if (strncmp(p, "on", 2) == 0)
384 fw_dump.fadump_enabled = 1;
385 else if (strncmp(p, "off", 3) == 0)
386 fw_dump.fadump_enabled = 0;
387
388 return 0;
389}
390early_param("fadump", early_fadump_param);
391
Hari Bathini81d9eca2017-05-22 15:04:23 +0530392/*
393 * Look for fadump_reserve_mem= cmdline option
394 * TODO: Remove references to 'fadump_reserve_mem=' parameter,
395 * the sooner 'crashkernel=' parameter is accustomed to.
396 */
397static int __init early_fadump_reserve_mem(char *p)
398{
399 if (p)
400 fw_dump.reserve_bootvar = memparse(p, &p);
401 return 0;
402}
403early_param("fadump_reserve_mem", early_fadump_reserve_mem);
404
Michal Suchanek98b8cd72017-05-27 17:46:15 +0200405static int register_fw_dump(struct fadump_mem_struct *fdm)
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000406{
Michal Suchanek98b8cd72017-05-27 17:46:15 +0200407 int rc, err;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000408 unsigned int wait_time;
409
410 pr_debug("Registering for firmware-assisted kernel dump...\n");
411
412 /* TODO: Add upper time limit for the delay */
413 do {
414 rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
415 FADUMP_REGISTER, fdm,
416 sizeof(struct fadump_mem_struct));
417
418 wait_time = rtas_busy_delay_time(rc);
419 if (wait_time)
420 mdelay(wait_time);
421
422 } while (wait_time);
423
Michal Suchanek98b8cd72017-05-27 17:46:15 +0200424 err = -EIO;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000425 switch (rc) {
Michal Suchanek98b8cd72017-05-27 17:46:15 +0200426 default:
427 pr_err("Failed to register. Unknown Error(%d).\n", rc);
428 break;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000429 case -1:
430 printk(KERN_ERR "Failed to register firmware-assisted kernel"
431 " dump. Hardware Error(%d).\n", rc);
432 break;
433 case -3:
434 printk(KERN_ERR "Failed to register firmware-assisted kernel"
435 " dump. Parameter Error(%d).\n", rc);
Michal Suchanek98b8cd72017-05-27 17:46:15 +0200436 err = -EINVAL;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000437 break;
438 case -9:
439 printk(KERN_ERR "firmware-assisted kernel dump is already "
440 " registered.");
441 fw_dump.dump_registered = 1;
Michal Suchanek98b8cd72017-05-27 17:46:15 +0200442 err = -EEXIST;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000443 break;
444 case 0:
445 printk(KERN_INFO "firmware-assisted kernel dump registration"
446 " is successful\n");
447 fw_dump.dump_registered = 1;
Michal Suchanek98b8cd72017-05-27 17:46:15 +0200448 err = 0;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000449 break;
450 }
Michal Suchanek98b8cd72017-05-27 17:46:15 +0200451 return err;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000452}
453
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000454void crash_fadump(struct pt_regs *regs, const char *str)
455{
456 struct fadump_crash_info_header *fdh = NULL;
Mahesh Salgaonkarf2a5e8f2016-10-24 23:51:51 +0530457 int old_cpu, this_cpu;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000458
459 if (!fw_dump.dump_registered || !fw_dump.fadumphdr_addr)
460 return;
461
Mahesh Salgaonkarf2a5e8f2016-10-24 23:51:51 +0530462 /*
463 * old_cpu == -1 means this is the first CPU which has come here,
464 * go ahead and trigger fadump.
465 *
466 * old_cpu != -1 means some other CPU has already on it's way
467 * to trigger fadump, just keep looping here.
468 */
469 this_cpu = smp_processor_id();
470 old_cpu = cmpxchg(&crashing_cpu, -1, this_cpu);
471
472 if (old_cpu != -1) {
473 /*
474 * We can't loop here indefinitely. Wait as long as fadump
475 * is in force. If we race with fadump un-registration this
476 * loop will break and then we go down to normal panic path
477 * and reboot. If fadump is in force the first crashing
478 * cpu will definitely trigger fadump.
479 */
480 while (fw_dump.dump_registered)
481 cpu_relax();
482 return;
483 }
484
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000485 fdh = __va(fw_dump.fadumphdr_addr);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000486 fdh->crashing_cpu = crashing_cpu;
487 crash_save_vmcoreinfo();
488
489 if (regs)
490 fdh->regs = *regs;
491 else
492 ppc_save_regs(&fdh->regs);
493
Rasmus Villemoesa0512162016-01-20 15:00:13 -0800494 fdh->online_mask = *cpu_online_mask;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000495
496 /* Call ibm,os-term rtas call to trigger firmware assisted dump */
497 rtas_os_term((char *)str);
498}
499
500#define GPR_MASK 0xffffff0000000000
501static inline int fadump_gpr_index(u64 id)
502{
503 int i = -1;
504 char str[3];
505
506 if ((id & GPR_MASK) == REG_ID("GPR")) {
507 /* get the digits at the end */
508 id &= ~GPR_MASK;
509 id >>= 24;
510 str[2] = '\0';
511 str[1] = id & 0xff;
512 str[0] = (id >> 8) & 0xff;
513 sscanf(str, "%d", &i);
514 if (i > 31)
515 i = -1;
516 }
517 return i;
518}
519
520static inline void fadump_set_regval(struct pt_regs *regs, u64 reg_id,
521 u64 reg_val)
522{
523 int i;
524
525 i = fadump_gpr_index(reg_id);
526 if (i >= 0)
527 regs->gpr[i] = (unsigned long)reg_val;
528 else if (reg_id == REG_ID("NIA"))
529 regs->nip = (unsigned long)reg_val;
530 else if (reg_id == REG_ID("MSR"))
531 regs->msr = (unsigned long)reg_val;
532 else if (reg_id == REG_ID("CTR"))
533 regs->ctr = (unsigned long)reg_val;
534 else if (reg_id == REG_ID("LR"))
535 regs->link = (unsigned long)reg_val;
536 else if (reg_id == REG_ID("XER"))
537 regs->xer = (unsigned long)reg_val;
538 else if (reg_id == REG_ID("CR"))
539 regs->ccr = (unsigned long)reg_val;
540 else if (reg_id == REG_ID("DAR"))
541 regs->dar = (unsigned long)reg_val;
542 else if (reg_id == REG_ID("DSISR"))
543 regs->dsisr = (unsigned long)reg_val;
544}
545
546static struct fadump_reg_entry*
547fadump_read_registers(struct fadump_reg_entry *reg_entry, struct pt_regs *regs)
548{
549 memset(regs, 0, sizeof(struct pt_regs));
550
Hari Bathini408cddd2014-10-01 12:32:30 +0530551 while (be64_to_cpu(reg_entry->reg_id) != REG_ID("CPUEND")) {
552 fadump_set_regval(regs, be64_to_cpu(reg_entry->reg_id),
553 be64_to_cpu(reg_entry->reg_value));
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000554 reg_entry++;
555 }
556 reg_entry++;
557 return reg_entry;
558}
559
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000560static u32 *fadump_regs_to_elf_notes(u32 *buf, struct pt_regs *regs)
561{
562 struct elf_prstatus prstatus;
563
564 memset(&prstatus, 0, sizeof(prstatus));
565 /*
566 * FIXME: How do i get PID? Do I really need it?
567 * prstatus.pr_pid = ????
568 */
569 elf_core_copy_kernel_regs(&prstatus.pr_reg, regs);
Hari Bathini22bd0172017-05-08 15:56:24 -0700570 buf = append_elf_note(buf, CRASH_CORE_NOTE_NAME, NT_PRSTATUS,
571 &prstatus, sizeof(prstatus));
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000572 return buf;
573}
574
575static void fadump_update_elfcore_header(char *bufp)
576{
577 struct elfhdr *elf;
578 struct elf_phdr *phdr;
579
580 elf = (struct elfhdr *)bufp;
581 bufp += sizeof(struct elfhdr);
582
583 /* First note is a place holder for cpu notes info. */
584 phdr = (struct elf_phdr *)bufp;
585
586 if (phdr->p_type == PT_NOTE) {
587 phdr->p_paddr = fw_dump.cpu_notes_buf;
588 phdr->p_offset = phdr->p_paddr;
589 phdr->p_filesz = fw_dump.cpu_notes_buf_size;
590 phdr->p_memsz = fw_dump.cpu_notes_buf_size;
591 }
592 return;
593}
594
595static void *fadump_cpu_notes_buf_alloc(unsigned long size)
596{
597 void *vaddr;
598 struct page *page;
599 unsigned long order, count, i;
600
601 order = get_order(size);
602 vaddr = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, order);
603 if (!vaddr)
604 return NULL;
605
606 count = 1 << order;
607 page = virt_to_page(vaddr);
608 for (i = 0; i < count; i++)
609 SetPageReserved(page + i);
610 return vaddr;
611}
612
613static void fadump_cpu_notes_buf_free(unsigned long vaddr, unsigned long size)
614{
615 struct page *page;
616 unsigned long order, count, i;
617
618 order = get_order(size);
619 count = 1 << order;
620 page = virt_to_page(vaddr);
621 for (i = 0; i < count; i++)
622 ClearPageReserved(page + i);
623 __free_pages(page, order);
624}
625
626/*
627 * Read CPU state dump data and convert it into ELF notes.
628 * The CPU dump starts with magic number "REGSAVE". NumCpusOffset should be
629 * used to access the data to allow for additional fields to be added without
630 * affecting compatibility. Each list of registers for a CPU starts with
631 * "CPUSTRT" and ends with "CPUEND". Each register entry is of 16 bytes,
632 * 8 Byte ASCII identifier and 8 Byte register value. The register entry
633 * with identifier "CPUSTRT" and "CPUEND" contains 4 byte cpu id as part
634 * of register value. For more details refer to PAPR document.
635 *
636 * Only for the crashing cpu we ignore the CPU dump data and get exact
637 * state from fadump crash info structure populated by first kernel at the
638 * time of crash.
639 */
640static int __init fadump_build_cpu_notes(const struct fadump_mem_struct *fdm)
641{
642 struct fadump_reg_save_area_header *reg_header;
643 struct fadump_reg_entry *reg_entry;
644 struct fadump_crash_info_header *fdh = NULL;
645 void *vaddr;
646 unsigned long addr;
647 u32 num_cpus, *note_buf;
648 struct pt_regs regs;
649 int i, rc = 0, cpu = 0;
650
651 if (!fdm->cpu_state_data.bytes_dumped)
652 return -EINVAL;
653
Hari Bathini408cddd2014-10-01 12:32:30 +0530654 addr = be64_to_cpu(fdm->cpu_state_data.destination_address);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000655 vaddr = __va(addr);
656
657 reg_header = vaddr;
Hari Bathini408cddd2014-10-01 12:32:30 +0530658 if (be64_to_cpu(reg_header->magic_number) != REGSAVE_AREA_MAGIC) {
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000659 printk(KERN_ERR "Unable to read register save area.\n");
660 return -ENOENT;
661 }
662 pr_debug("--------CPU State Data------------\n");
Hari Bathini408cddd2014-10-01 12:32:30 +0530663 pr_debug("Magic Number: %llx\n", be64_to_cpu(reg_header->magic_number));
664 pr_debug("NumCpuOffset: %x\n", be32_to_cpu(reg_header->num_cpu_offset));
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000665
Hari Bathini408cddd2014-10-01 12:32:30 +0530666 vaddr += be32_to_cpu(reg_header->num_cpu_offset);
667 num_cpus = be32_to_cpu(*((__be32 *)(vaddr)));
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000668 pr_debug("NumCpus : %u\n", num_cpus);
669 vaddr += sizeof(u32);
670 reg_entry = (struct fadump_reg_entry *)vaddr;
671
672 /* Allocate buffer to hold cpu crash notes. */
673 fw_dump.cpu_notes_buf_size = num_cpus * sizeof(note_buf_t);
674 fw_dump.cpu_notes_buf_size = PAGE_ALIGN(fw_dump.cpu_notes_buf_size);
675 note_buf = fadump_cpu_notes_buf_alloc(fw_dump.cpu_notes_buf_size);
676 if (!note_buf) {
677 printk(KERN_ERR "Failed to allocate 0x%lx bytes for "
678 "cpu notes buffer\n", fw_dump.cpu_notes_buf_size);
679 return -ENOMEM;
680 }
681 fw_dump.cpu_notes_buf = __pa(note_buf);
682
683 pr_debug("Allocated buffer for cpu notes of size %ld at %p\n",
684 (num_cpus * sizeof(note_buf_t)), note_buf);
685
686 if (fw_dump.fadumphdr_addr)
687 fdh = __va(fw_dump.fadumphdr_addr);
688
689 for (i = 0; i < num_cpus; i++) {
Hari Bathini408cddd2014-10-01 12:32:30 +0530690 if (be64_to_cpu(reg_entry->reg_id) != REG_ID("CPUSTRT")) {
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000691 printk(KERN_ERR "Unable to read CPU state data\n");
692 rc = -ENOENT;
693 goto error_out;
694 }
695 /* Lower 4 bytes of reg_value contains logical cpu id */
Hari Bathini408cddd2014-10-01 12:32:30 +0530696 cpu = be64_to_cpu(reg_entry->reg_value) & FADUMP_CPU_ID_MASK;
Rasmus Villemoesa0512162016-01-20 15:00:13 -0800697 if (fdh && !cpumask_test_cpu(cpu, &fdh->online_mask)) {
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000698 SKIP_TO_NEXT_CPU(reg_entry);
699 continue;
700 }
701 pr_debug("Reading register data for cpu %d...\n", cpu);
702 if (fdh && fdh->crashing_cpu == cpu) {
703 regs = fdh->regs;
704 note_buf = fadump_regs_to_elf_notes(note_buf, &regs);
705 SKIP_TO_NEXT_CPU(reg_entry);
706 } else {
707 reg_entry++;
708 reg_entry = fadump_read_registers(reg_entry, &regs);
709 note_buf = fadump_regs_to_elf_notes(note_buf, &regs);
710 }
711 }
Hari Bathini22bd0172017-05-08 15:56:24 -0700712 final_note(note_buf);
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000713
Rickard Strandqvistb717d982014-05-23 00:03:16 +0200714 if (fdh) {
715 pr_debug("Updating elfcore header (%llx) with cpu notes\n",
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000716 fdh->elfcorehdr_addr);
Rickard Strandqvistb717d982014-05-23 00:03:16 +0200717 fadump_update_elfcore_header((char *)__va(fdh->elfcorehdr_addr));
718 }
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000719 return 0;
720
721error_out:
722 fadump_cpu_notes_buf_free((unsigned long)__va(fw_dump.cpu_notes_buf),
723 fw_dump.cpu_notes_buf_size);
724 fw_dump.cpu_notes_buf = 0;
725 fw_dump.cpu_notes_buf_size = 0;
726 return rc;
727
728}
729
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000730/*
731 * Validate and process the dump data stored by firmware before exporting
732 * it through '/proc/vmcore'.
733 */
734static int __init process_fadump(const struct fadump_mem_struct *fdm_active)
735{
736 struct fadump_crash_info_header *fdh;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000737 int rc = 0;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000738
739 if (!fdm_active || !fw_dump.fadumphdr_addr)
740 return -EINVAL;
741
742 /* Check if the dump data is valid. */
Hari Bathini408cddd2014-10-01 12:32:30 +0530743 if ((be16_to_cpu(fdm_active->header.dump_status_flag) == FADUMP_ERROR_FLAG) ||
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000744 (fdm_active->cpu_state_data.error_flags != 0) ||
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000745 (fdm_active->rmr_region.error_flags != 0)) {
746 printk(KERN_ERR "Dump taken by platform is not valid\n");
747 return -EINVAL;
748 }
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000749 if ((fdm_active->rmr_region.bytes_dumped !=
750 fdm_active->rmr_region.source_len) ||
751 !fdm_active->cpu_state_data.bytes_dumped) {
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000752 printk(KERN_ERR "Dump taken by platform is incomplete\n");
753 return -EINVAL;
754 }
755
756 /* Validate the fadump crash info header */
757 fdh = __va(fw_dump.fadumphdr_addr);
758 if (fdh->magic_number != FADUMP_CRASH_INFO_MAGIC) {
759 printk(KERN_ERR "Crash info header is not valid.\n");
760 return -EINVAL;
761 }
762
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000763 rc = fadump_build_cpu_notes(fdm_active);
764 if (rc)
765 return rc;
766
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000767 /*
768 * We are done validating dump info and elfcore header is now ready
769 * to be exported. set elfcorehdr_addr so that vmcore module will
770 * export the elfcore header through '/proc/vmcore'.
771 */
772 elfcorehdr_addr = fdh->elfcorehdr_addr;
773
774 return 0;
775}
776
777static inline void fadump_add_crash_memory(unsigned long long base,
778 unsigned long long end)
779{
780 if (base == end)
781 return;
782
783 pr_debug("crash_memory_range[%d] [%#016llx-%#016llx], %#llx bytes\n",
784 crash_mem_ranges, base, end - 1, (end - base));
785 crash_memory_ranges[crash_mem_ranges].base = base;
786 crash_memory_ranges[crash_mem_ranges].size = end - base;
787 crash_mem_ranges++;
788}
789
790static void fadump_exclude_reserved_area(unsigned long long start,
791 unsigned long long end)
792{
793 unsigned long long ra_start, ra_end;
794
795 ra_start = fw_dump.reserve_dump_area_start;
796 ra_end = ra_start + fw_dump.reserve_dump_area_size;
797
798 if ((ra_start < end) && (ra_end > start)) {
799 if ((start < ra_start) && (end > ra_end)) {
800 fadump_add_crash_memory(start, ra_start);
801 fadump_add_crash_memory(ra_end, end);
802 } else if (start < ra_start) {
803 fadump_add_crash_memory(start, ra_start);
804 } else if (ra_end < end) {
805 fadump_add_crash_memory(ra_end, end);
806 }
807 } else
808 fadump_add_crash_memory(start, end);
809}
810
811static int fadump_init_elfcore_header(char *bufp)
812{
813 struct elfhdr *elf;
814
815 elf = (struct elfhdr *) bufp;
816 bufp += sizeof(struct elfhdr);
817 memcpy(elf->e_ident, ELFMAG, SELFMAG);
818 elf->e_ident[EI_CLASS] = ELF_CLASS;
819 elf->e_ident[EI_DATA] = ELF_DATA;
820 elf->e_ident[EI_VERSION] = EV_CURRENT;
821 elf->e_ident[EI_OSABI] = ELF_OSABI;
822 memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
823 elf->e_type = ET_CORE;
824 elf->e_machine = ELF_ARCH;
825 elf->e_version = EV_CURRENT;
826 elf->e_entry = 0;
827 elf->e_phoff = sizeof(struct elfhdr);
828 elf->e_shoff = 0;
Daniel Axtensd8bced22016-09-06 15:32:42 +1000829#if defined(_CALL_ELF)
830 elf->e_flags = _CALL_ELF;
831#else
832 elf->e_flags = 0;
833#endif
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000834 elf->e_ehsize = sizeof(struct elfhdr);
835 elf->e_phentsize = sizeof(struct elf_phdr);
836 elf->e_phnum = 0;
837 elf->e_shentsize = 0;
838 elf->e_shnum = 0;
839 elf->e_shstrndx = 0;
840
841 return 0;
842}
843
844/*
845 * Traverse through memblock structure and setup crash memory ranges. These
846 * ranges will be used create PT_LOAD program headers in elfcore header.
847 */
848static void fadump_setup_crash_memory_ranges(void)
849{
850 struct memblock_region *reg;
851 unsigned long long start, end;
852
853 pr_debug("Setup crash memory ranges.\n");
854 crash_mem_ranges = 0;
855 /*
856 * add the first memory chunk (RMA_START through boot_memory_size) as
857 * a separate memory chunk. The reason is, at the time crash firmware
858 * will move the content of this memory chunk to different location
859 * specified during fadump registration. We need to create a separate
860 * program header for this chunk with the correct offset.
861 */
862 fadump_add_crash_memory(RMA_START, fw_dump.boot_memory_size);
863
864 for_each_memblock(memory, reg) {
865 start = (unsigned long long)reg->base;
866 end = start + (unsigned long long)reg->size;
867 if (start == RMA_START && end >= fw_dump.boot_memory_size)
868 start = fw_dump.boot_memory_size;
869
870 /* add this range excluding the reserved dump area. */
871 fadump_exclude_reserved_area(start, end);
872 }
873}
874
Mahesh Salgaonkard34c5f22012-02-16 01:14:53 +0000875/*
876 * If the given physical address falls within the boot memory region then
877 * return the relocated address that points to the dump region reserved
878 * for saving initial boot memory contents.
879 */
880static inline unsigned long fadump_relocate(unsigned long paddr)
881{
882 if (paddr > RMA_START && paddr < fw_dump.boot_memory_size)
Hari Bathini408cddd2014-10-01 12:32:30 +0530883 return be64_to_cpu(fdm.rmr_region.destination_address) + paddr;
Mahesh Salgaonkard34c5f22012-02-16 01:14:53 +0000884 else
885 return paddr;
886}
887
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000888static int fadump_create_elfcore_headers(char *bufp)
889{
890 struct elfhdr *elf;
891 struct elf_phdr *phdr;
892 int i;
893
894 fadump_init_elfcore_header(bufp);
895 elf = (struct elfhdr *)bufp;
896 bufp += sizeof(struct elfhdr);
897
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000898 /*
899 * setup ELF PT_NOTE, place holder for cpu notes info. The notes info
900 * will be populated during second kernel boot after crash. Hence
901 * this PT_NOTE will always be the first elf note.
902 *
903 * NOTE: Any new ELF note addition should be placed after this note.
904 */
905 phdr = (struct elf_phdr *)bufp;
906 bufp += sizeof(struct elf_phdr);
907 phdr->p_type = PT_NOTE;
908 phdr->p_flags = 0;
909 phdr->p_vaddr = 0;
910 phdr->p_align = 0;
911
912 phdr->p_offset = 0;
913 phdr->p_paddr = 0;
914 phdr->p_filesz = 0;
915 phdr->p_memsz = 0;
916
917 (elf->e_phnum)++;
918
Mahesh Salgaonkard34c5f22012-02-16 01:14:53 +0000919 /* setup ELF PT_NOTE for vmcoreinfo */
920 phdr = (struct elf_phdr *)bufp;
921 bufp += sizeof(struct elf_phdr);
922 phdr->p_type = PT_NOTE;
923 phdr->p_flags = 0;
924 phdr->p_vaddr = 0;
925 phdr->p_align = 0;
926
927 phdr->p_paddr = fadump_relocate(paddr_vmcoreinfo_note());
928 phdr->p_offset = phdr->p_paddr;
929 phdr->p_memsz = vmcoreinfo_max_size;
930 phdr->p_filesz = vmcoreinfo_max_size;
931
932 /* Increment number of program headers. */
933 (elf->e_phnum)++;
934
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000935 /* setup PT_LOAD sections. */
936
937 for (i = 0; i < crash_mem_ranges; i++) {
938 unsigned long long mbase, msize;
939 mbase = crash_memory_ranges[i].base;
940 msize = crash_memory_ranges[i].size;
941
942 if (!msize)
943 continue;
944
945 phdr = (struct elf_phdr *)bufp;
946 bufp += sizeof(struct elf_phdr);
947 phdr->p_type = PT_LOAD;
948 phdr->p_flags = PF_R|PF_W|PF_X;
949 phdr->p_offset = mbase;
950
951 if (mbase == RMA_START) {
952 /*
953 * The entire RMA region will be moved by firmware
954 * to the specified destination_address. Hence set
955 * the correct offset.
956 */
Hari Bathini408cddd2014-10-01 12:32:30 +0530957 phdr->p_offset = be64_to_cpu(fdm.rmr_region.destination_address);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000958 }
959
960 phdr->p_paddr = mbase;
961 phdr->p_vaddr = (unsigned long)__va(mbase);
962 phdr->p_filesz = msize;
963 phdr->p_memsz = msize;
964 phdr->p_align = 0;
965
966 /* Increment number of program headers. */
967 (elf->e_phnum)++;
968 }
969 return 0;
970}
971
972static unsigned long init_fadump_header(unsigned long addr)
973{
974 struct fadump_crash_info_header *fdh;
975
976 if (!addr)
977 return 0;
978
979 fw_dump.fadumphdr_addr = addr;
980 fdh = __va(addr);
981 addr += sizeof(struct fadump_crash_info_header);
982
983 memset(fdh, 0, sizeof(struct fadump_crash_info_header));
984 fdh->magic_number = FADUMP_CRASH_INFO_MAGIC;
985 fdh->elfcorehdr_addr = addr;
Mahesh Salgaonkarebaeb5a2012-02-16 01:14:45 +0000986 /* We will set the crashing cpu id in crash_fadump() during crash. */
987 fdh->crashing_cpu = CPU_UNKNOWN;
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000988
989 return addr;
990}
991
Michal Suchanek98b8cd72017-05-27 17:46:15 +0200992static int register_fadump(void)
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000993{
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +0000994 unsigned long addr;
995 void *vaddr;
996
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +0000997 /*
998 * If no memory is reserved then we can not register for firmware-
999 * assisted dump.
1000 */
1001 if (!fw_dump.reserve_dump_area_size)
Michal Suchanek98b8cd72017-05-27 17:46:15 +02001002 return -ENODEV;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001003
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +00001004 fadump_setup_crash_memory_ranges();
1005
Hari Bathini408cddd2014-10-01 12:32:30 +05301006 addr = be64_to_cpu(fdm.rmr_region.destination_address) + be64_to_cpu(fdm.rmr_region.source_len);
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +00001007 /* Initialize fadump crash info header. */
1008 addr = init_fadump_header(addr);
1009 vaddr = __va(addr);
1010
1011 pr_debug("Creating ELF core headers at %#016lx\n", addr);
1012 fadump_create_elfcore_headers(vaddr);
1013
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001014 /* register the future kernel dump with firmware. */
Michal Suchanek98b8cd72017-05-27 17:46:15 +02001015 return register_fw_dump(&fdm);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001016}
1017
1018static int fadump_unregister_dump(struct fadump_mem_struct *fdm)
1019{
1020 int rc = 0;
1021 unsigned int wait_time;
1022
1023 pr_debug("Un-register firmware-assisted dump\n");
1024
1025 /* TODO: Add upper time limit for the delay */
1026 do {
1027 rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
1028 FADUMP_UNREGISTER, fdm,
1029 sizeof(struct fadump_mem_struct));
1030
1031 wait_time = rtas_busy_delay_time(rc);
1032 if (wait_time)
1033 mdelay(wait_time);
1034 } while (wait_time);
1035
1036 if (rc) {
1037 printk(KERN_ERR "Failed to un-register firmware-assisted dump."
1038 " unexpected error(%d).\n", rc);
1039 return rc;
1040 }
1041 fw_dump.dump_registered = 0;
1042 return 0;
1043}
1044
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001045static int fadump_invalidate_dump(struct fadump_mem_struct *fdm)
1046{
1047 int rc = 0;
1048 unsigned int wait_time;
1049
1050 pr_debug("Invalidating firmware-assisted dump registration\n");
1051
1052 /* TODO: Add upper time limit for the delay */
1053 do {
1054 rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
1055 FADUMP_INVALIDATE, fdm,
1056 sizeof(struct fadump_mem_struct));
1057
1058 wait_time = rtas_busy_delay_time(rc);
1059 if (wait_time)
1060 mdelay(wait_time);
1061 } while (wait_time);
1062
1063 if (rc) {
Colin Ian King4a037492016-06-27 12:07:41 +01001064 pr_err("Failed to invalidate firmware-assisted dump registration. Unexpected error (%d).\n", rc);
Michael Ellermanb5b1cfc2016-07-05 23:45:56 +10001065 return rc;
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001066 }
1067 fw_dump.dump_active = 0;
1068 fdm_active = NULL;
1069 return 0;
1070}
1071
1072void fadump_cleanup(void)
1073{
1074 /* Invalidate the registration only if dump is active. */
1075 if (fw_dump.dump_active) {
1076 init_fadump_mem_struct(&fdm,
Hari Bathini408cddd2014-10-01 12:32:30 +05301077 be64_to_cpu(fdm_active->cpu_state_data.destination_address));
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001078 fadump_invalidate_dump(&fdm);
1079 }
1080}
1081
1082/*
1083 * Release the memory that was reserved in early boot to preserve the memory
1084 * contents. The released memory will be available for general use.
1085 */
1086static void fadump_release_memory(unsigned long begin, unsigned long end)
1087{
1088 unsigned long addr;
1089 unsigned long ra_start, ra_end;
1090
1091 ra_start = fw_dump.reserve_dump_area_start;
1092 ra_end = ra_start + fw_dump.reserve_dump_area_size;
1093
1094 for (addr = begin; addr < end; addr += PAGE_SIZE) {
1095 /*
1096 * exclude the dump reserve area. Will reuse it for next
1097 * fadump registration.
1098 */
1099 if (addr <= ra_end && ((addr + PAGE_SIZE) > ra_start))
1100 continue;
1101
Jiang Liu5d585e52013-04-29 15:06:47 -07001102 free_reserved_page(pfn_to_page(addr >> PAGE_SHIFT));
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001103 }
1104}
1105
1106static void fadump_invalidate_release_mem(void)
1107{
1108 unsigned long reserved_area_start, reserved_area_end;
1109 unsigned long destination_address;
1110
1111 mutex_lock(&fadump_mutex);
1112 if (!fw_dump.dump_active) {
1113 mutex_unlock(&fadump_mutex);
1114 return;
1115 }
1116
Hari Bathini408cddd2014-10-01 12:32:30 +05301117 destination_address = be64_to_cpu(fdm_active->cpu_state_data.destination_address);
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001118 fadump_cleanup();
1119 mutex_unlock(&fadump_mutex);
1120
1121 /*
1122 * Save the current reserved memory bounds we will require them
1123 * later for releasing the memory for general use.
1124 */
1125 reserved_area_start = fw_dump.reserve_dump_area_start;
1126 reserved_area_end = reserved_area_start +
1127 fw_dump.reserve_dump_area_size;
1128 /*
1129 * Setup reserve_dump_area_start and its size so that we can
1130 * reuse this reserved memory for Re-registration.
1131 */
1132 fw_dump.reserve_dump_area_start = destination_address;
1133 fw_dump.reserve_dump_area_size = get_fadump_area_size();
1134
1135 fadump_release_memory(reserved_area_start, reserved_area_end);
1136 if (fw_dump.cpu_notes_buf) {
1137 fadump_cpu_notes_buf_free(
1138 (unsigned long)__va(fw_dump.cpu_notes_buf),
1139 fw_dump.cpu_notes_buf_size);
1140 fw_dump.cpu_notes_buf = 0;
1141 fw_dump.cpu_notes_buf_size = 0;
1142 }
1143 /* Initialize the kernel dump memory structure for FAD registration. */
1144 init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);
1145}
1146
1147static ssize_t fadump_release_memory_store(struct kobject *kobj,
1148 struct kobj_attribute *attr,
1149 const char *buf, size_t count)
1150{
1151 if (!fw_dump.dump_active)
1152 return -EPERM;
1153
1154 if (buf[0] == '1') {
1155 /*
1156 * Take away the '/proc/vmcore'. We are releasing the dump
1157 * memory, hence it will not be valid anymore.
1158 */
Michael Ellerman2685f822016-09-30 10:51:46 +10001159#ifdef CONFIG_PROC_VMCORE
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001160 vmcore_cleanup();
Michael Ellerman2685f822016-09-30 10:51:46 +10001161#endif
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001162 fadump_invalidate_release_mem();
1163
1164 } else
1165 return -EINVAL;
1166 return count;
1167}
1168
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001169static ssize_t fadump_enabled_show(struct kobject *kobj,
1170 struct kobj_attribute *attr,
1171 char *buf)
1172{
1173 return sprintf(buf, "%d\n", fw_dump.fadump_enabled);
1174}
1175
1176static ssize_t fadump_register_show(struct kobject *kobj,
1177 struct kobj_attribute *attr,
1178 char *buf)
1179{
1180 return sprintf(buf, "%d\n", fw_dump.dump_registered);
1181}
1182
1183static ssize_t fadump_register_store(struct kobject *kobj,
1184 struct kobj_attribute *attr,
1185 const char *buf, size_t count)
1186{
1187 int ret = 0;
1188
1189 if (!fw_dump.fadump_enabled || fdm_active)
1190 return -EPERM;
1191
1192 mutex_lock(&fadump_mutex);
1193
1194 switch (buf[0]) {
1195 case '0':
1196 if (fw_dump.dump_registered == 0) {
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001197 goto unlock_out;
1198 }
1199 /* Un-register Firmware-assisted dump */
1200 fadump_unregister_dump(&fdm);
1201 break;
1202 case '1':
1203 if (fw_dump.dump_registered == 1) {
Michal Suchanek98b8cd72017-05-27 17:46:15 +02001204 ret = -EEXIST;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001205 goto unlock_out;
1206 }
1207 /* Register Firmware-assisted dump */
Michal Suchanek98b8cd72017-05-27 17:46:15 +02001208 ret = register_fadump();
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001209 break;
1210 default:
1211 ret = -EINVAL;
1212 break;
1213 }
1214
1215unlock_out:
1216 mutex_unlock(&fadump_mutex);
1217 return ret < 0 ? ret : count;
1218}
1219
1220static int fadump_region_show(struct seq_file *m, void *private)
1221{
1222 const struct fadump_mem_struct *fdm_ptr;
1223
1224 if (!fw_dump.fadump_enabled)
1225 return 0;
1226
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001227 mutex_lock(&fadump_mutex);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001228 if (fdm_active)
1229 fdm_ptr = fdm_active;
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001230 else {
1231 mutex_unlock(&fadump_mutex);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001232 fdm_ptr = &fdm;
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001233 }
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001234
1235 seq_printf(m,
1236 "CPU : [%#016llx-%#016llx] %#llx bytes, "
1237 "Dumped: %#llx\n",
Hari Bathini408cddd2014-10-01 12:32:30 +05301238 be64_to_cpu(fdm_ptr->cpu_state_data.destination_address),
1239 be64_to_cpu(fdm_ptr->cpu_state_data.destination_address) +
1240 be64_to_cpu(fdm_ptr->cpu_state_data.source_len) - 1,
1241 be64_to_cpu(fdm_ptr->cpu_state_data.source_len),
1242 be64_to_cpu(fdm_ptr->cpu_state_data.bytes_dumped));
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001243 seq_printf(m,
1244 "HPTE: [%#016llx-%#016llx] %#llx bytes, "
1245 "Dumped: %#llx\n",
Hari Bathini408cddd2014-10-01 12:32:30 +05301246 be64_to_cpu(fdm_ptr->hpte_region.destination_address),
1247 be64_to_cpu(fdm_ptr->hpte_region.destination_address) +
1248 be64_to_cpu(fdm_ptr->hpte_region.source_len) - 1,
1249 be64_to_cpu(fdm_ptr->hpte_region.source_len),
1250 be64_to_cpu(fdm_ptr->hpte_region.bytes_dumped));
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001251 seq_printf(m,
1252 "DUMP: [%#016llx-%#016llx] %#llx bytes, "
1253 "Dumped: %#llx\n",
Hari Bathini408cddd2014-10-01 12:32:30 +05301254 be64_to_cpu(fdm_ptr->rmr_region.destination_address),
1255 be64_to_cpu(fdm_ptr->rmr_region.destination_address) +
1256 be64_to_cpu(fdm_ptr->rmr_region.source_len) - 1,
1257 be64_to_cpu(fdm_ptr->rmr_region.source_len),
1258 be64_to_cpu(fdm_ptr->rmr_region.bytes_dumped));
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001259
1260 if (!fdm_active ||
1261 (fw_dump.reserve_dump_area_start ==
Hari Bathini408cddd2014-10-01 12:32:30 +05301262 be64_to_cpu(fdm_ptr->cpu_state_data.destination_address)))
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001263 goto out;
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001264
1265 /* Dump is active. Show reserved memory region. */
1266 seq_printf(m,
1267 " : [%#016llx-%#016llx] %#llx bytes, "
1268 "Dumped: %#llx\n",
1269 (unsigned long long)fw_dump.reserve_dump_area_start,
Hari Bathini408cddd2014-10-01 12:32:30 +05301270 be64_to_cpu(fdm_ptr->cpu_state_data.destination_address) - 1,
1271 be64_to_cpu(fdm_ptr->cpu_state_data.destination_address) -
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001272 fw_dump.reserve_dump_area_start,
Hari Bathini408cddd2014-10-01 12:32:30 +05301273 be64_to_cpu(fdm_ptr->cpu_state_data.destination_address) -
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001274 fw_dump.reserve_dump_area_start);
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001275out:
1276 if (fdm_active)
1277 mutex_unlock(&fadump_mutex);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001278 return 0;
1279}
1280
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001281static struct kobj_attribute fadump_release_attr = __ATTR(fadump_release_mem,
1282 0200, NULL,
1283 fadump_release_memory_store);
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001284static struct kobj_attribute fadump_attr = __ATTR(fadump_enabled,
1285 0444, fadump_enabled_show,
1286 NULL);
1287static struct kobj_attribute fadump_register_attr = __ATTR(fadump_registered,
1288 0644, fadump_register_show,
1289 fadump_register_store);
1290
1291static int fadump_region_open(struct inode *inode, struct file *file)
1292{
1293 return single_open(file, fadump_region_show, inode->i_private);
1294}
1295
1296static const struct file_operations fadump_region_fops = {
1297 .open = fadump_region_open,
1298 .read = seq_read,
1299 .llseek = seq_lseek,
1300 .release = single_release,
1301};
1302
1303static void fadump_init_files(void)
1304{
1305 struct dentry *debugfs_file;
1306 int rc = 0;
1307
1308 rc = sysfs_create_file(kernel_kobj, &fadump_attr.attr);
1309 if (rc)
1310 printk(KERN_ERR "fadump: unable to create sysfs file"
1311 " fadump_enabled (%d)\n", rc);
1312
1313 rc = sysfs_create_file(kernel_kobj, &fadump_register_attr.attr);
1314 if (rc)
1315 printk(KERN_ERR "fadump: unable to create sysfs file"
1316 " fadump_registered (%d)\n", rc);
1317
1318 debugfs_file = debugfs_create_file("fadump_region", 0444,
1319 powerpc_debugfs_root, NULL,
1320 &fadump_region_fops);
1321 if (!debugfs_file)
1322 printk(KERN_ERR "fadump: unable to create debugfs file"
1323 " fadump_region\n");
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001324
1325 if (fw_dump.dump_active) {
1326 rc = sysfs_create_file(kernel_kobj, &fadump_release_attr.attr);
1327 if (rc)
1328 printk(KERN_ERR "fadump: unable to create sysfs file"
1329 " fadump_release_mem (%d)\n", rc);
1330 }
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001331 return;
1332}
1333
1334/*
1335 * Prepare for firmware-assisted dump.
1336 */
1337int __init setup_fadump(void)
1338{
1339 if (!fw_dump.fadump_enabled)
1340 return 0;
1341
1342 if (!fw_dump.fadump_supported) {
1343 printk(KERN_ERR "Firmware-assisted dump is not supported on"
1344 " this hardware\n");
1345 return 0;
1346 }
1347
1348 fadump_show_config();
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +00001349 /*
1350 * If dump data is available then see if it is valid and prepare for
1351 * saving it to the disk.
1352 */
Mahesh Salgaonkarb500aff2012-02-16 01:15:08 +00001353 if (fw_dump.dump_active) {
1354 /*
1355 * if dump process fails then invalidate the registration
1356 * and release memory before proceeding for re-registration.
1357 */
1358 if (process_fadump(fdm_active) < 0)
1359 fadump_invalidate_release_mem();
1360 }
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001361 /* Initialize the kernel dump memory structure for FAD registration. */
Mahesh Salgaonkar2df173d2012-02-16 01:14:37 +00001362 else if (fw_dump.reserve_dump_area_size)
Mahesh Salgaonkar3ccc00a2012-02-20 02:15:03 +00001363 init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);
1364 fadump_init_files();
1365
1366 return 1;
1367}
1368subsys_initcall(setup_fadump);