1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * crash.c - kernel crash support code. 4 * Copyright (C) 2002-2004 Eric Biederman <ebiederm@xmission.com> 5 */ 6 7#include <linux/buildid.h> 8#include <linux/init.h> 9#include <linux/utsname.h> 10#include <linux/vmalloc.h> 11#include <linux/sizes.h> 12#include <linux/kexec.h> 13#include <linux/memory.h> 14#include <linux/cpuhotplug.h> 15#include <linux/memblock.h> 16#include <linux/kmemleak.h> 17 18#include <asm/page.h> 19#include <asm/sections.h> 20 21#include <crypto/sha1.h> 22 23#include "kallsyms_internal.h" 24#include "kexec_internal.h" 25 26/* vmcoreinfo stuff */ 27unsigned char *vmcoreinfo_data; 28size_t vmcoreinfo_size; 29u32 *vmcoreinfo_note; 30 31/* trusted vmcoreinfo, e.g. we can make a copy in the crash memory */ 32static unsigned char *vmcoreinfo_data_safecopy; 33 34Elf_Word *append_elf_note(Elf_Word *buf, char *name, unsigned int type, 35 void *data, size_t data_len) 36{ 37 struct elf_note *note = (struct elf_note *)buf; 38 39 note->n_namesz = strlen(name) + 1; 40 note->n_descsz = data_len; 41 note->n_type = type; 42 buf += DIV_ROUND_UP(sizeof(*note), sizeof(Elf_Word)); 43 memcpy(buf, name, note->n_namesz); 44 buf += DIV_ROUND_UP(note->n_namesz, sizeof(Elf_Word)); 45 memcpy(buf, data, data_len); 46 buf += DIV_ROUND_UP(data_len, sizeof(Elf_Word)); 47 48 return buf; 49} 50 51void final_note(Elf_Word *buf) 52{ 53 memset(buf, 0, sizeof(struct elf_note)); 54} 55 56static void update_vmcoreinfo_note(void) 57{ 58 u32 *buf = vmcoreinfo_note; 59 60 if (!vmcoreinfo_size) 61 return; 62 buf = append_elf_note(buf, VMCOREINFO_NOTE_NAME, 0, vmcoreinfo_data, 63 vmcoreinfo_size); 64 final_note(buf); 65} 66 67void crash_update_vmcoreinfo_safecopy(void *ptr) 68{ 69 if (ptr) 70 memcpy(ptr, vmcoreinfo_data, vmcoreinfo_size); 71 72 vmcoreinfo_data_safecopy = ptr; 73} 74 75void crash_save_vmcoreinfo(void) 76{ 77 if (!vmcoreinfo_note) 78 return; 79 80 /* Use the safe copy to generate vmcoreinfo note if have */ 81 if (vmcoreinfo_data_safecopy) 82 vmcoreinfo_data = vmcoreinfo_data_safecopy; 83 84 vmcoreinfo_append_str("CRASHTIME=%lld\n", ktime_get_real_seconds()); 85 update_vmcoreinfo_note(); 86} 87 88void vmcoreinfo_append_str(const char *fmt, ...) 89{ 90 va_list args; 91 char buf[0x50]; 92 size_t r; 93 94 va_start(args, fmt); 95 r = vscnprintf(buf, sizeof(buf), fmt, args); 96 va_end(args); 97 98 r = min(r, (size_t)VMCOREINFO_BYTES - vmcoreinfo_size); 99 100 memcpy(&vmcoreinfo_data[vmcoreinfo_size], buf, r); 101 102 vmcoreinfo_size += r; 103 104 WARN_ONCE(vmcoreinfo_size == VMCOREINFO_BYTES, 105 "vmcoreinfo data exceeds allocated size, truncating"); 106} 107 108/* 109 * provide an empty default implementation here -- architecture 110 * code may override this 111 */ 112void __weak arch_crash_save_vmcoreinfo(void) 113{} 114 115phys_addr_t __weak paddr_vmcoreinfo_note(void) 116{ 117 return __pa(vmcoreinfo_note); 118} 119EXPORT_SYMBOL(paddr_vmcoreinfo_note); 120 121static int __init crash_save_vmcoreinfo_init(void) 122{ 123 vmcoreinfo_data = (unsigned char *)get_zeroed_page(GFP_KERNEL); 124 if (!vmcoreinfo_data) { 125 pr_warn("Memory allocation for vmcoreinfo_data failed\n"); 126 return -ENOMEM; 127 } 128 129 vmcoreinfo_note = alloc_pages_exact(VMCOREINFO_NOTE_SIZE, 130 GFP_KERNEL | __GFP_ZERO); 131 if (!vmcoreinfo_note) { 132 free_page((unsigned long)vmcoreinfo_data); 133 vmcoreinfo_data = NULL; 134 pr_warn("Memory allocation for vmcoreinfo_note failed\n"); 135 return -ENOMEM; 136 } 137 138 VMCOREINFO_OSRELEASE(init_uts_ns.name.release); 139 VMCOREINFO_BUILD_ID(); 140 VMCOREINFO_PAGESIZE(PAGE_SIZE); 141 142 VMCOREINFO_SYMBOL(init_uts_ns); 143 VMCOREINFO_OFFSET(uts_namespace, name); 144 VMCOREINFO_SYMBOL(node_online_map); 145#ifdef CONFIG_MMU 146 VMCOREINFO_SYMBOL_ARRAY(swapper_pg_dir); 147#endif 148 VMCOREINFO_SYMBOL(_stext); 149 vmcoreinfo_append_str("NUMBER(VMALLOC_START)=0x%lx\n", (unsigned long) VMALLOC_START); 150 151#ifndef CONFIG_NUMA 152 VMCOREINFO_SYMBOL(mem_map); 153 VMCOREINFO_SYMBOL(contig_page_data); 154#endif 155#ifdef CONFIG_SPARSEMEM_VMEMMAP 156 VMCOREINFO_SYMBOL_ARRAY(vmemmap); 157#endif 158#ifdef CONFIG_SPARSEMEM 159 VMCOREINFO_SYMBOL_ARRAY(mem_section); 160 VMCOREINFO_LENGTH(mem_section, NR_SECTION_ROOTS); 161 VMCOREINFO_STRUCT_SIZE(mem_section); 162 VMCOREINFO_OFFSET(mem_section, section_mem_map); 163 VMCOREINFO_NUMBER(SECTION_SIZE_BITS); 164 VMCOREINFO_NUMBER(MAX_PHYSMEM_BITS); 165#endif 166 VMCOREINFO_STRUCT_SIZE(page); 167 VMCOREINFO_STRUCT_SIZE(pglist_data); 168 VMCOREINFO_STRUCT_SIZE(zone); 169 VMCOREINFO_STRUCT_SIZE(free_area); 170 VMCOREINFO_STRUCT_SIZE(list_head); 171 VMCOREINFO_SIZE(nodemask_t); 172 VMCOREINFO_OFFSET(page, flags); 173 VMCOREINFO_OFFSET(page, _refcount); 174 VMCOREINFO_OFFSET(page, mapping); 175 VMCOREINFO_OFFSET(page, lru); 176 VMCOREINFO_OFFSET(page, _mapcount); 177 VMCOREINFO_OFFSET(page, private); 178 VMCOREINFO_OFFSET(page, compound_head); 179 VMCOREINFO_OFFSET(pglist_data, node_zones); 180 VMCOREINFO_OFFSET(pglist_data, nr_zones); 181#ifdef CONFIG_FLATMEM 182 VMCOREINFO_OFFSET(pglist_data, node_mem_map); 183#endif 184 VMCOREINFO_OFFSET(pglist_data, node_start_pfn); 185 VMCOREINFO_OFFSET(pglist_data, node_spanned_pages); 186 VMCOREINFO_OFFSET(pglist_data, node_id); 187 VMCOREINFO_OFFSET(zone, free_area); 188 VMCOREINFO_OFFSET(zone, vm_stat); 189 VMCOREINFO_OFFSET(zone, spanned_pages); 190 VMCOREINFO_OFFSET(free_area, free_list); 191 VMCOREINFO_OFFSET(list_head, next); 192 VMCOREINFO_OFFSET(list_head, prev); 193 VMCOREINFO_LENGTH(zone.free_area, NR_PAGE_ORDERS); 194 log_buf_vmcoreinfo_setup(); 195 VMCOREINFO_LENGTH(free_area.free_list, MIGRATE_TYPES); 196 VMCOREINFO_NUMBER(NR_FREE_PAGES); 197 VMCOREINFO_NUMBER(PG_lru); 198 VMCOREINFO_NUMBER(PG_private); 199 VMCOREINFO_NUMBER(PG_swapcache); 200 VMCOREINFO_NUMBER(PG_swapbacked); 201 VMCOREINFO_NUMBER(PG_slab); 202#ifdef CONFIG_MEMORY_FAILURE 203 VMCOREINFO_NUMBER(PG_hwpoison); 204#endif 205 VMCOREINFO_NUMBER(PG_head_mask); 206#define PAGE_BUDDY_MAPCOUNT_VALUE (~PG_buddy) 207 VMCOREINFO_NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE); 208#define PAGE_HUGETLB_MAPCOUNT_VALUE (~PG_hugetlb) 209 VMCOREINFO_NUMBER(PAGE_HUGETLB_MAPCOUNT_VALUE); 210#define PAGE_OFFLINE_MAPCOUNT_VALUE (~PG_offline) 211 VMCOREINFO_NUMBER(PAGE_OFFLINE_MAPCOUNT_VALUE); 212 213#ifdef CONFIG_KALLSYMS 214 VMCOREINFO_SYMBOL(kallsyms_names); 215 VMCOREINFO_SYMBOL(kallsyms_num_syms); 216 VMCOREINFO_SYMBOL(kallsyms_token_table); 217 VMCOREINFO_SYMBOL(kallsyms_token_index); 218#ifdef CONFIG_KALLSYMS_BASE_RELATIVE 219 VMCOREINFO_SYMBOL(kallsyms_offsets); 220 VMCOREINFO_SYMBOL(kallsyms_relative_base); 221#else 222 VMCOREINFO_SYMBOL(kallsyms_addresses); 223#endif /* CONFIG_KALLSYMS_BASE_RELATIVE */ 224#endif /* CONFIG_KALLSYMS */ 225 226 arch_crash_save_vmcoreinfo(); 227 update_vmcoreinfo_note(); 228 229 return 0; 230} 231 232subsys_initcall(crash_save_vmcoreinfo_init); 233