xref: /linux/kernel/vmcore_info.c (revision d3246b6ee42a155ab57e936841028fff3d7d98b4)
1443cbaf9SBaoquan He // SPDX-License-Identifier: GPL-2.0-only
2443cbaf9SBaoquan He /*
3443cbaf9SBaoquan He  * crash.c - kernel crash support code.
4443cbaf9SBaoquan He  * Copyright (C) 2002-2004 Eric Biederman  <ebiederm@xmission.com>
5443cbaf9SBaoquan He  */
6443cbaf9SBaoquan He 
7443cbaf9SBaoquan He #include <linux/buildid.h>
8443cbaf9SBaoquan He #include <linux/init.h>
9443cbaf9SBaoquan He #include <linux/utsname.h>
10443cbaf9SBaoquan He #include <linux/vmalloc.h>
11443cbaf9SBaoquan He #include <linux/sizes.h>
12443cbaf9SBaoquan He #include <linux/kexec.h>
13443cbaf9SBaoquan He #include <linux/memory.h>
14443cbaf9SBaoquan He #include <linux/cpuhotplug.h>
15443cbaf9SBaoquan He #include <linux/memblock.h>
16443cbaf9SBaoquan He #include <linux/kmemleak.h>
17443cbaf9SBaoquan He 
18443cbaf9SBaoquan He #include <asm/page.h>
19443cbaf9SBaoquan He #include <asm/sections.h>
20443cbaf9SBaoquan He 
21443cbaf9SBaoquan He #include <crypto/sha1.h>
22443cbaf9SBaoquan He 
23443cbaf9SBaoquan He #include "kallsyms_internal.h"
24443cbaf9SBaoquan He #include "kexec_internal.h"
25443cbaf9SBaoquan He 
26443cbaf9SBaoquan He /* vmcoreinfo stuff */
27443cbaf9SBaoquan He unsigned char *vmcoreinfo_data;
28443cbaf9SBaoquan He size_t vmcoreinfo_size;
29443cbaf9SBaoquan He u32 *vmcoreinfo_note;
30443cbaf9SBaoquan He 
31443cbaf9SBaoquan He /* trusted vmcoreinfo, e.g. we can make a copy in the crash memory */
32443cbaf9SBaoquan He static unsigned char *vmcoreinfo_data_safecopy;
33443cbaf9SBaoquan He 
34443cbaf9SBaoquan He Elf_Word *append_elf_note(Elf_Word *buf, char *name, unsigned int type,
35443cbaf9SBaoquan He 			  void *data, size_t data_len)
36443cbaf9SBaoquan He {
37443cbaf9SBaoquan He 	struct elf_note *note = (struct elf_note *)buf;
38443cbaf9SBaoquan He 
39443cbaf9SBaoquan He 	note->n_namesz = strlen(name) + 1;
40443cbaf9SBaoquan He 	note->n_descsz = data_len;
41443cbaf9SBaoquan He 	note->n_type   = type;
42443cbaf9SBaoquan He 	buf += DIV_ROUND_UP(sizeof(*note), sizeof(Elf_Word));
43443cbaf9SBaoquan He 	memcpy(buf, name, note->n_namesz);
44443cbaf9SBaoquan He 	buf += DIV_ROUND_UP(note->n_namesz, sizeof(Elf_Word));
45443cbaf9SBaoquan He 	memcpy(buf, data, data_len);
46443cbaf9SBaoquan He 	buf += DIV_ROUND_UP(data_len, sizeof(Elf_Word));
47443cbaf9SBaoquan He 
48443cbaf9SBaoquan He 	return buf;
49443cbaf9SBaoquan He }
50443cbaf9SBaoquan He 
51443cbaf9SBaoquan He void final_note(Elf_Word *buf)
52443cbaf9SBaoquan He {
53443cbaf9SBaoquan He 	memset(buf, 0, sizeof(struct elf_note));
54443cbaf9SBaoquan He }
55443cbaf9SBaoquan He 
56443cbaf9SBaoquan He static void update_vmcoreinfo_note(void)
57443cbaf9SBaoquan He {
58443cbaf9SBaoquan He 	u32 *buf = vmcoreinfo_note;
59443cbaf9SBaoquan He 
60443cbaf9SBaoquan He 	if (!vmcoreinfo_size)
61443cbaf9SBaoquan He 		return;
62443cbaf9SBaoquan He 	buf = append_elf_note(buf, VMCOREINFO_NOTE_NAME, 0, vmcoreinfo_data,
63443cbaf9SBaoquan He 			      vmcoreinfo_size);
64443cbaf9SBaoquan He 	final_note(buf);
65443cbaf9SBaoquan He }
66443cbaf9SBaoquan He 
67443cbaf9SBaoquan He void crash_update_vmcoreinfo_safecopy(void *ptr)
68443cbaf9SBaoquan He {
69443cbaf9SBaoquan He 	if (ptr)
70443cbaf9SBaoquan He 		memcpy(ptr, vmcoreinfo_data, vmcoreinfo_size);
71443cbaf9SBaoquan He 
72443cbaf9SBaoquan He 	vmcoreinfo_data_safecopy = ptr;
73443cbaf9SBaoquan He }
74443cbaf9SBaoquan He 
75443cbaf9SBaoquan He void crash_save_vmcoreinfo(void)
76443cbaf9SBaoquan He {
77443cbaf9SBaoquan He 	if (!vmcoreinfo_note)
78443cbaf9SBaoquan He 		return;
79443cbaf9SBaoquan He 
80443cbaf9SBaoquan He 	/* Use the safe copy to generate vmcoreinfo note if have */
81443cbaf9SBaoquan He 	if (vmcoreinfo_data_safecopy)
82443cbaf9SBaoquan He 		vmcoreinfo_data = vmcoreinfo_data_safecopy;
83443cbaf9SBaoquan He 
84443cbaf9SBaoquan He 	vmcoreinfo_append_str("CRASHTIME=%lld\n", ktime_get_real_seconds());
85443cbaf9SBaoquan He 	update_vmcoreinfo_note();
86443cbaf9SBaoquan He }
87443cbaf9SBaoquan He 
88443cbaf9SBaoquan He void vmcoreinfo_append_str(const char *fmt, ...)
89443cbaf9SBaoquan He {
90443cbaf9SBaoquan He 	va_list args;
91443cbaf9SBaoquan He 	char buf[0x50];
92443cbaf9SBaoquan He 	size_t r;
93443cbaf9SBaoquan He 
94443cbaf9SBaoquan He 	va_start(args, fmt);
95443cbaf9SBaoquan He 	r = vscnprintf(buf, sizeof(buf), fmt, args);
96443cbaf9SBaoquan He 	va_end(args);
97443cbaf9SBaoquan He 
98443cbaf9SBaoquan He 	r = min(r, (size_t)VMCOREINFO_BYTES - vmcoreinfo_size);
99443cbaf9SBaoquan He 
100443cbaf9SBaoquan He 	memcpy(&vmcoreinfo_data[vmcoreinfo_size], buf, r);
101443cbaf9SBaoquan He 
102443cbaf9SBaoquan He 	vmcoreinfo_size += r;
103443cbaf9SBaoquan He 
104443cbaf9SBaoquan He 	WARN_ONCE(vmcoreinfo_size == VMCOREINFO_BYTES,
105443cbaf9SBaoquan He 		  "vmcoreinfo data exceeds allocated size, truncating");
106443cbaf9SBaoquan He }
107443cbaf9SBaoquan He 
108443cbaf9SBaoquan He /*
109443cbaf9SBaoquan He  * provide an empty default implementation here -- architecture
110443cbaf9SBaoquan He  * code may override this
111443cbaf9SBaoquan He  */
112443cbaf9SBaoquan He void __weak arch_crash_save_vmcoreinfo(void)
113443cbaf9SBaoquan He {}
114443cbaf9SBaoquan He 
115443cbaf9SBaoquan He phys_addr_t __weak paddr_vmcoreinfo_note(void)
116443cbaf9SBaoquan He {
117443cbaf9SBaoquan He 	return __pa(vmcoreinfo_note);
118443cbaf9SBaoquan He }
119443cbaf9SBaoquan He EXPORT_SYMBOL(paddr_vmcoreinfo_note);
120443cbaf9SBaoquan He 
121443cbaf9SBaoquan He static int __init crash_save_vmcoreinfo_init(void)
122443cbaf9SBaoquan He {
123443cbaf9SBaoquan He 	vmcoreinfo_data = (unsigned char *)get_zeroed_page(GFP_KERNEL);
124443cbaf9SBaoquan He 	if (!vmcoreinfo_data) {
125443cbaf9SBaoquan He 		pr_warn("Memory allocation for vmcoreinfo_data failed\n");
126443cbaf9SBaoquan He 		return -ENOMEM;
127443cbaf9SBaoquan He 	}
128443cbaf9SBaoquan He 
129443cbaf9SBaoquan He 	vmcoreinfo_note = alloc_pages_exact(VMCOREINFO_NOTE_SIZE,
130443cbaf9SBaoquan He 						GFP_KERNEL | __GFP_ZERO);
131443cbaf9SBaoquan He 	if (!vmcoreinfo_note) {
132443cbaf9SBaoquan He 		free_page((unsigned long)vmcoreinfo_data);
133443cbaf9SBaoquan He 		vmcoreinfo_data = NULL;
134443cbaf9SBaoquan He 		pr_warn("Memory allocation for vmcoreinfo_note failed\n");
135443cbaf9SBaoquan He 		return -ENOMEM;
136443cbaf9SBaoquan He 	}
137443cbaf9SBaoquan He 
138443cbaf9SBaoquan He 	VMCOREINFO_OSRELEASE(init_uts_ns.name.release);
139443cbaf9SBaoquan He 	VMCOREINFO_BUILD_ID();
140443cbaf9SBaoquan He 	VMCOREINFO_PAGESIZE(PAGE_SIZE);
141443cbaf9SBaoquan He 
142443cbaf9SBaoquan He 	VMCOREINFO_SYMBOL(init_uts_ns);
143443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(uts_namespace, name);
144443cbaf9SBaoquan He 	VMCOREINFO_SYMBOL(node_online_map);
145443cbaf9SBaoquan He #ifdef CONFIG_MMU
146443cbaf9SBaoquan He 	VMCOREINFO_SYMBOL_ARRAY(swapper_pg_dir);
147443cbaf9SBaoquan He #endif
148443cbaf9SBaoquan He 	VMCOREINFO_SYMBOL(_stext);
149443cbaf9SBaoquan He 	vmcoreinfo_append_str("NUMBER(VMALLOC_START)=0x%lx\n", (unsigned long) VMALLOC_START);
150443cbaf9SBaoquan He 
151443cbaf9SBaoquan He #ifndef CONFIG_NUMA
152443cbaf9SBaoquan He 	VMCOREINFO_SYMBOL(mem_map);
153443cbaf9SBaoquan He 	VMCOREINFO_SYMBOL(contig_page_data);
154443cbaf9SBaoquan He #endif
155*d3246b6eSHuang Shijie #ifdef CONFIG_SPARSEMEM_VMEMMAP
156*d3246b6eSHuang Shijie 	VMCOREINFO_SYMBOL_ARRAY(vmemmap);
157*d3246b6eSHuang Shijie #endif
158443cbaf9SBaoquan He #ifdef CONFIG_SPARSEMEM
159443cbaf9SBaoquan He 	VMCOREINFO_SYMBOL_ARRAY(mem_section);
160443cbaf9SBaoquan He 	VMCOREINFO_LENGTH(mem_section, NR_SECTION_ROOTS);
161443cbaf9SBaoquan He 	VMCOREINFO_STRUCT_SIZE(mem_section);
162443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(mem_section, section_mem_map);
163443cbaf9SBaoquan He 	VMCOREINFO_NUMBER(SECTION_SIZE_BITS);
164443cbaf9SBaoquan He 	VMCOREINFO_NUMBER(MAX_PHYSMEM_BITS);
165443cbaf9SBaoquan He #endif
166443cbaf9SBaoquan He 	VMCOREINFO_STRUCT_SIZE(page);
167443cbaf9SBaoquan He 	VMCOREINFO_STRUCT_SIZE(pglist_data);
168443cbaf9SBaoquan He 	VMCOREINFO_STRUCT_SIZE(zone);
169443cbaf9SBaoquan He 	VMCOREINFO_STRUCT_SIZE(free_area);
170443cbaf9SBaoquan He 	VMCOREINFO_STRUCT_SIZE(list_head);
171443cbaf9SBaoquan He 	VMCOREINFO_SIZE(nodemask_t);
172443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(page, flags);
173443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(page, _refcount);
174443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(page, mapping);
175443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(page, lru);
176443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(page, _mapcount);
177443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(page, private);
178443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(page, compound_head);
179443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(pglist_data, node_zones);
180443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(pglist_data, nr_zones);
181443cbaf9SBaoquan He #ifdef CONFIG_FLATMEM
182443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(pglist_data, node_mem_map);
183443cbaf9SBaoquan He #endif
184443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(pglist_data, node_start_pfn);
185443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(pglist_data, node_spanned_pages);
186443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(pglist_data, node_id);
187443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(zone, free_area);
188443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(zone, vm_stat);
189443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(zone, spanned_pages);
190443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(free_area, free_list);
191443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(list_head, next);
192443cbaf9SBaoquan He 	VMCOREINFO_OFFSET(list_head, prev);
193443cbaf9SBaoquan He 	VMCOREINFO_LENGTH(zone.free_area, NR_PAGE_ORDERS);
194443cbaf9SBaoquan He 	log_buf_vmcoreinfo_setup();
195443cbaf9SBaoquan He 	VMCOREINFO_LENGTH(free_area.free_list, MIGRATE_TYPES);
196443cbaf9SBaoquan He 	VMCOREINFO_NUMBER(NR_FREE_PAGES);
197443cbaf9SBaoquan He 	VMCOREINFO_NUMBER(PG_lru);
198443cbaf9SBaoquan He 	VMCOREINFO_NUMBER(PG_private);
199443cbaf9SBaoquan He 	VMCOREINFO_NUMBER(PG_swapcache);
200443cbaf9SBaoquan He 	VMCOREINFO_NUMBER(PG_swapbacked);
201443cbaf9SBaoquan He 	VMCOREINFO_NUMBER(PG_slab);
202443cbaf9SBaoquan He #ifdef CONFIG_MEMORY_FAILURE
203443cbaf9SBaoquan He 	VMCOREINFO_NUMBER(PG_hwpoison);
204443cbaf9SBaoquan He #endif
205443cbaf9SBaoquan He 	VMCOREINFO_NUMBER(PG_head_mask);
206443cbaf9SBaoquan He #define PAGE_BUDDY_MAPCOUNT_VALUE	(~PG_buddy)
207443cbaf9SBaoquan He 	VMCOREINFO_NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE);
208443cbaf9SBaoquan He #ifdef CONFIG_HUGETLB_PAGE
209443cbaf9SBaoquan He 	VMCOREINFO_NUMBER(PG_hugetlb);
210443cbaf9SBaoquan He #define PAGE_OFFLINE_MAPCOUNT_VALUE	(~PG_offline)
211443cbaf9SBaoquan He 	VMCOREINFO_NUMBER(PAGE_OFFLINE_MAPCOUNT_VALUE);
212443cbaf9SBaoquan He #endif
213443cbaf9SBaoquan He 
214443cbaf9SBaoquan He #ifdef CONFIG_KALLSYMS
215443cbaf9SBaoquan He 	VMCOREINFO_SYMBOL(kallsyms_names);
216443cbaf9SBaoquan He 	VMCOREINFO_SYMBOL(kallsyms_num_syms);
217443cbaf9SBaoquan He 	VMCOREINFO_SYMBOL(kallsyms_token_table);
218443cbaf9SBaoquan He 	VMCOREINFO_SYMBOL(kallsyms_token_index);
219443cbaf9SBaoquan He #ifdef CONFIG_KALLSYMS_BASE_RELATIVE
220443cbaf9SBaoquan He 	VMCOREINFO_SYMBOL(kallsyms_offsets);
221443cbaf9SBaoquan He 	VMCOREINFO_SYMBOL(kallsyms_relative_base);
222443cbaf9SBaoquan He #else
223443cbaf9SBaoquan He 	VMCOREINFO_SYMBOL(kallsyms_addresses);
224443cbaf9SBaoquan He #endif /* CONFIG_KALLSYMS_BASE_RELATIVE */
225443cbaf9SBaoquan He #endif /* CONFIG_KALLSYMS */
226443cbaf9SBaoquan He 
227443cbaf9SBaoquan He 	arch_crash_save_vmcoreinfo();
228443cbaf9SBaoquan He 	update_vmcoreinfo_note();
229443cbaf9SBaoquan He 
230443cbaf9SBaoquan He 	return 0;
231443cbaf9SBaoquan He }
232443cbaf9SBaoquan He 
233443cbaf9SBaoquan He subsys_initcall(crash_save_vmcoreinfo_init);
234