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 <[email protected]>
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
append_elf_note(Elf_Word * buf,char * name,unsigned int type,void * data,size_t data_len)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
final_note(Elf_Word * buf)51443cbaf9SBaoquan He void final_note(Elf_Word *buf)
52443cbaf9SBaoquan He {
53443cbaf9SBaoquan He memset(buf, 0, sizeof(struct elf_note));
54443cbaf9SBaoquan He }
55443cbaf9SBaoquan He
update_vmcoreinfo_note(void)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
crash_update_vmcoreinfo_safecopy(void * ptr)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
crash_save_vmcoreinfo(void)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
vmcoreinfo_append_str(const char * fmt,...)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 */
arch_crash_save_vmcoreinfo(void)112443cbaf9SBaoquan He void __weak arch_crash_save_vmcoreinfo(void)
113443cbaf9SBaoquan He {}
114443cbaf9SBaoquan He
paddr_vmcoreinfo_note(void)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
crash_save_vmcoreinfo_init(void)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
155d3246b6eSHuang Shijie #ifdef CONFIG_SPARSEMEM_VMEMMAP
156d3246b6eSHuang Shijie VMCOREINFO_SYMBOL_ARRAY(vmemmap);
157d3246b6eSHuang 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);
201*4ffca5a9SMatthew Wilcox (Oracle) #define PAGE_SLAB_MAPCOUNT_VALUE (PGTY_slab << 24)
20246df8e73SMatthew Wilcox (Oracle) VMCOREINFO_NUMBER(PAGE_SLAB_MAPCOUNT_VALUE);
203443cbaf9SBaoquan He #ifdef CONFIG_MEMORY_FAILURE
204443cbaf9SBaoquan He VMCOREINFO_NUMBER(PG_hwpoison);
205443cbaf9SBaoquan He #endif
206443cbaf9SBaoquan He VMCOREINFO_NUMBER(PG_head_mask);
207*4ffca5a9SMatthew Wilcox (Oracle) #define PAGE_BUDDY_MAPCOUNT_VALUE (PGTY_buddy << 24)
208443cbaf9SBaoquan He VMCOREINFO_NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE);
209*4ffca5a9SMatthew Wilcox (Oracle) #define PAGE_HUGETLB_MAPCOUNT_VALUE (PGTY_hugetlb << 24)
210d99e3140SMatthew Wilcox (Oracle) VMCOREINFO_NUMBER(PAGE_HUGETLB_MAPCOUNT_VALUE);
211*4ffca5a9SMatthew Wilcox (Oracle) #define PAGE_OFFLINE_MAPCOUNT_VALUE (PGTY_offline << 24)
212443cbaf9SBaoquan He VMCOREINFO_NUMBER(PAGE_OFFLINE_MAPCOUNT_VALUE);
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 VMCOREINFO_SYMBOL(kallsyms_offsets);
220443cbaf9SBaoquan He VMCOREINFO_SYMBOL(kallsyms_relative_base);
221443cbaf9SBaoquan He #endif /* CONFIG_KALLSYMS */
222443cbaf9SBaoquan He
223443cbaf9SBaoquan He arch_crash_save_vmcoreinfo();
224443cbaf9SBaoquan He update_vmcoreinfo_note();
225443cbaf9SBaoquan He
226443cbaf9SBaoquan He return 0;
227443cbaf9SBaoquan He }
228443cbaf9SBaoquan He
229443cbaf9SBaoquan He subsys_initcall(crash_save_vmcoreinfo_init);
230