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