Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * crash.c - kernel crash support code.
0004  * Copyright (C) 2002-2004 Eric Biederman  <ebiederm@xmission.com>
0005  */
0006 
0007 #include <linux/buildid.h>
0008 #include <linux/crash_core.h>
0009 #include <linux/init.h>
0010 #include <linux/utsname.h>
0011 #include <linux/vmalloc.h>
0012 #include <linux/sizes.h>
0013 
0014 #include <asm/page.h>
0015 #include <asm/sections.h>
0016 
0017 #include <crypto/sha1.h>
0018 
0019 #include "kallsyms_internal.h"
0020 
0021 /* vmcoreinfo stuff */
0022 unsigned char *vmcoreinfo_data;
0023 size_t vmcoreinfo_size;
0024 u32 *vmcoreinfo_note;
0025 
0026 /* trusted vmcoreinfo, e.g. we can make a copy in the crash memory */
0027 static unsigned char *vmcoreinfo_data_safecopy;
0028 
0029 /*
0030  * parsing the "crashkernel" commandline
0031  *
0032  * this code is intended to be called from architecture specific code
0033  */
0034 
0035 
0036 /*
0037  * This function parses command lines in the format
0038  *
0039  *   crashkernel=ramsize-range:size[,...][@offset]
0040  *
0041  * The function returns 0 on success and -EINVAL on failure.
0042  */
0043 static int __init parse_crashkernel_mem(char *cmdline,
0044                     unsigned long long system_ram,
0045                     unsigned long long *crash_size,
0046                     unsigned long long *crash_base)
0047 {
0048     char *cur = cmdline, *tmp;
0049     unsigned long long total_mem = system_ram;
0050 
0051     /*
0052      * Firmware sometimes reserves some memory regions for its own use,
0053      * so the system memory size is less than the actual physical memory
0054      * size. Work around this by rounding up the total size to 128M,
0055      * which is enough for most test cases.
0056      */
0057     total_mem = roundup(total_mem, SZ_128M);
0058 
0059     /* for each entry of the comma-separated list */
0060     do {
0061         unsigned long long start, end = ULLONG_MAX, size;
0062 
0063         /* get the start of the range */
0064         start = memparse(cur, &tmp);
0065         if (cur == tmp) {
0066             pr_warn("crashkernel: Memory value expected\n");
0067             return -EINVAL;
0068         }
0069         cur = tmp;
0070         if (*cur != '-') {
0071             pr_warn("crashkernel: '-' expected\n");
0072             return -EINVAL;
0073         }
0074         cur++;
0075 
0076         /* if no ':' is here, than we read the end */
0077         if (*cur != ':') {
0078             end = memparse(cur, &tmp);
0079             if (cur == tmp) {
0080                 pr_warn("crashkernel: Memory value expected\n");
0081                 return -EINVAL;
0082             }
0083             cur = tmp;
0084             if (end <= start) {
0085                 pr_warn("crashkernel: end <= start\n");
0086                 return -EINVAL;
0087             }
0088         }
0089 
0090         if (*cur != ':') {
0091             pr_warn("crashkernel: ':' expected\n");
0092             return -EINVAL;
0093         }
0094         cur++;
0095 
0096         size = memparse(cur, &tmp);
0097         if (cur == tmp) {
0098             pr_warn("Memory value expected\n");
0099             return -EINVAL;
0100         }
0101         cur = tmp;
0102         if (size >= total_mem) {
0103             pr_warn("crashkernel: invalid size\n");
0104             return -EINVAL;
0105         }
0106 
0107         /* match ? */
0108         if (total_mem >= start && total_mem < end) {
0109             *crash_size = size;
0110             break;
0111         }
0112     } while (*cur++ == ',');
0113 
0114     if (*crash_size > 0) {
0115         while (*cur && *cur != ' ' && *cur != '@')
0116             cur++;
0117         if (*cur == '@') {
0118             cur++;
0119             *crash_base = memparse(cur, &tmp);
0120             if (cur == tmp) {
0121                 pr_warn("Memory value expected after '@'\n");
0122                 return -EINVAL;
0123             }
0124         }
0125     } else
0126         pr_info("crashkernel size resulted in zero bytes\n");
0127 
0128     return 0;
0129 }
0130 
0131 /*
0132  * That function parses "simple" (old) crashkernel command lines like
0133  *
0134  *  crashkernel=size[@offset]
0135  *
0136  * It returns 0 on success and -EINVAL on failure.
0137  */
0138 static int __init parse_crashkernel_simple(char *cmdline,
0139                        unsigned long long *crash_size,
0140                        unsigned long long *crash_base)
0141 {
0142     char *cur = cmdline;
0143 
0144     *crash_size = memparse(cmdline, &cur);
0145     if (cmdline == cur) {
0146         pr_warn("crashkernel: memory value expected\n");
0147         return -EINVAL;
0148     }
0149 
0150     if (*cur == '@')
0151         *crash_base = memparse(cur+1, &cur);
0152     else if (*cur != ' ' && *cur != '\0') {
0153         pr_warn("crashkernel: unrecognized char: %c\n", *cur);
0154         return -EINVAL;
0155     }
0156 
0157     return 0;
0158 }
0159 
0160 #define SUFFIX_HIGH 0
0161 #define SUFFIX_LOW  1
0162 #define SUFFIX_NULL 2
0163 static __initdata char *suffix_tbl[] = {
0164     [SUFFIX_HIGH] = ",high",
0165     [SUFFIX_LOW]  = ",low",
0166     [SUFFIX_NULL] = NULL,
0167 };
0168 
0169 /*
0170  * That function parses "suffix"  crashkernel command lines like
0171  *
0172  *  crashkernel=size,[high|low]
0173  *
0174  * It returns 0 on success and -EINVAL on failure.
0175  */
0176 static int __init parse_crashkernel_suffix(char *cmdline,
0177                        unsigned long long   *crash_size,
0178                        const char *suffix)
0179 {
0180     char *cur = cmdline;
0181 
0182     *crash_size = memparse(cmdline, &cur);
0183     if (cmdline == cur) {
0184         pr_warn("crashkernel: memory value expected\n");
0185         return -EINVAL;
0186     }
0187 
0188     /* check with suffix */
0189     if (strncmp(cur, suffix, strlen(suffix))) {
0190         pr_warn("crashkernel: unrecognized char: %c\n", *cur);
0191         return -EINVAL;
0192     }
0193     cur += strlen(suffix);
0194     if (*cur != ' ' && *cur != '\0') {
0195         pr_warn("crashkernel: unrecognized char: %c\n", *cur);
0196         return -EINVAL;
0197     }
0198 
0199     return 0;
0200 }
0201 
0202 static __init char *get_last_crashkernel(char *cmdline,
0203                  const char *name,
0204                  const char *suffix)
0205 {
0206     char *p = cmdline, *ck_cmdline = NULL;
0207 
0208     /* find crashkernel and use the last one if there are more */
0209     p = strstr(p, name);
0210     while (p) {
0211         char *end_p = strchr(p, ' ');
0212         char *q;
0213 
0214         if (!end_p)
0215             end_p = p + strlen(p);
0216 
0217         if (!suffix) {
0218             int i;
0219 
0220             /* skip the one with any known suffix */
0221             for (i = 0; suffix_tbl[i]; i++) {
0222                 q = end_p - strlen(suffix_tbl[i]);
0223                 if (!strncmp(q, suffix_tbl[i],
0224                          strlen(suffix_tbl[i])))
0225                     goto next;
0226             }
0227             ck_cmdline = p;
0228         } else {
0229             q = end_p - strlen(suffix);
0230             if (!strncmp(q, suffix, strlen(suffix)))
0231                 ck_cmdline = p;
0232         }
0233 next:
0234         p = strstr(p+1, name);
0235     }
0236 
0237     return ck_cmdline;
0238 }
0239 
0240 static int __init __parse_crashkernel(char *cmdline,
0241                  unsigned long long system_ram,
0242                  unsigned long long *crash_size,
0243                  unsigned long long *crash_base,
0244                  const char *name,
0245                  const char *suffix)
0246 {
0247     char    *first_colon, *first_space;
0248     char    *ck_cmdline;
0249 
0250     BUG_ON(!crash_size || !crash_base);
0251     *crash_size = 0;
0252     *crash_base = 0;
0253 
0254     ck_cmdline = get_last_crashkernel(cmdline, name, suffix);
0255     if (!ck_cmdline)
0256         return -ENOENT;
0257 
0258     ck_cmdline += strlen(name);
0259 
0260     if (suffix)
0261         return parse_crashkernel_suffix(ck_cmdline, crash_size,
0262                 suffix);
0263     /*
0264      * if the commandline contains a ':', then that's the extended
0265      * syntax -- if not, it must be the classic syntax
0266      */
0267     first_colon = strchr(ck_cmdline, ':');
0268     first_space = strchr(ck_cmdline, ' ');
0269     if (first_colon && (!first_space || first_colon < first_space))
0270         return parse_crashkernel_mem(ck_cmdline, system_ram,
0271                 crash_size, crash_base);
0272 
0273     return parse_crashkernel_simple(ck_cmdline, crash_size, crash_base);
0274 }
0275 
0276 /*
0277  * That function is the entry point for command line parsing and should be
0278  * called from the arch-specific code.
0279  */
0280 int __init parse_crashkernel(char *cmdline,
0281                  unsigned long long system_ram,
0282                  unsigned long long *crash_size,
0283                  unsigned long long *crash_base)
0284 {
0285     return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
0286                     "crashkernel=", NULL);
0287 }
0288 
0289 int __init parse_crashkernel_high(char *cmdline,
0290                  unsigned long long system_ram,
0291                  unsigned long long *crash_size,
0292                  unsigned long long *crash_base)
0293 {
0294     return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
0295                 "crashkernel=", suffix_tbl[SUFFIX_HIGH]);
0296 }
0297 
0298 int __init parse_crashkernel_low(char *cmdline,
0299                  unsigned long long system_ram,
0300                  unsigned long long *crash_size,
0301                  unsigned long long *crash_base)
0302 {
0303     return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
0304                 "crashkernel=", suffix_tbl[SUFFIX_LOW]);
0305 }
0306 
0307 /*
0308  * Add a dummy early_param handler to mark crashkernel= as a known command line
0309  * parameter and suppress incorrect warnings in init/main.c.
0310  */
0311 static int __init parse_crashkernel_dummy(char *arg)
0312 {
0313     return 0;
0314 }
0315 early_param("crashkernel", parse_crashkernel_dummy);
0316 
0317 Elf_Word *append_elf_note(Elf_Word *buf, char *name, unsigned int type,
0318               void *data, size_t data_len)
0319 {
0320     struct elf_note *note = (struct elf_note *)buf;
0321 
0322     note->n_namesz = strlen(name) + 1;
0323     note->n_descsz = data_len;
0324     note->n_type   = type;
0325     buf += DIV_ROUND_UP(sizeof(*note), sizeof(Elf_Word));
0326     memcpy(buf, name, note->n_namesz);
0327     buf += DIV_ROUND_UP(note->n_namesz, sizeof(Elf_Word));
0328     memcpy(buf, data, data_len);
0329     buf += DIV_ROUND_UP(data_len, sizeof(Elf_Word));
0330 
0331     return buf;
0332 }
0333 
0334 void final_note(Elf_Word *buf)
0335 {
0336     memset(buf, 0, sizeof(struct elf_note));
0337 }
0338 
0339 static void update_vmcoreinfo_note(void)
0340 {
0341     u32 *buf = vmcoreinfo_note;
0342 
0343     if (!vmcoreinfo_size)
0344         return;
0345     buf = append_elf_note(buf, VMCOREINFO_NOTE_NAME, 0, vmcoreinfo_data,
0346                   vmcoreinfo_size);
0347     final_note(buf);
0348 }
0349 
0350 void crash_update_vmcoreinfo_safecopy(void *ptr)
0351 {
0352     if (ptr)
0353         memcpy(ptr, vmcoreinfo_data, vmcoreinfo_size);
0354 
0355     vmcoreinfo_data_safecopy = ptr;
0356 }
0357 
0358 void crash_save_vmcoreinfo(void)
0359 {
0360     if (!vmcoreinfo_note)
0361         return;
0362 
0363     /* Use the safe copy to generate vmcoreinfo note if have */
0364     if (vmcoreinfo_data_safecopy)
0365         vmcoreinfo_data = vmcoreinfo_data_safecopy;
0366 
0367     vmcoreinfo_append_str("CRASHTIME=%lld\n", ktime_get_real_seconds());
0368     update_vmcoreinfo_note();
0369 }
0370 
0371 void vmcoreinfo_append_str(const char *fmt, ...)
0372 {
0373     va_list args;
0374     char buf[0x50];
0375     size_t r;
0376 
0377     va_start(args, fmt);
0378     r = vscnprintf(buf, sizeof(buf), fmt, args);
0379     va_end(args);
0380 
0381     r = min(r, (size_t)VMCOREINFO_BYTES - vmcoreinfo_size);
0382 
0383     memcpy(&vmcoreinfo_data[vmcoreinfo_size], buf, r);
0384 
0385     vmcoreinfo_size += r;
0386 }
0387 
0388 /*
0389  * provide an empty default implementation here -- architecture
0390  * code may override this
0391  */
0392 void __weak arch_crash_save_vmcoreinfo(void)
0393 {}
0394 
0395 phys_addr_t __weak paddr_vmcoreinfo_note(void)
0396 {
0397     return __pa(vmcoreinfo_note);
0398 }
0399 EXPORT_SYMBOL(paddr_vmcoreinfo_note);
0400 
0401 static int __init crash_save_vmcoreinfo_init(void)
0402 {
0403     vmcoreinfo_data = (unsigned char *)get_zeroed_page(GFP_KERNEL);
0404     if (!vmcoreinfo_data) {
0405         pr_warn("Memory allocation for vmcoreinfo_data failed\n");
0406         return -ENOMEM;
0407     }
0408 
0409     vmcoreinfo_note = alloc_pages_exact(VMCOREINFO_NOTE_SIZE,
0410                         GFP_KERNEL | __GFP_ZERO);
0411     if (!vmcoreinfo_note) {
0412         free_page((unsigned long)vmcoreinfo_data);
0413         vmcoreinfo_data = NULL;
0414         pr_warn("Memory allocation for vmcoreinfo_note failed\n");
0415         return -ENOMEM;
0416     }
0417 
0418     VMCOREINFO_OSRELEASE(init_uts_ns.name.release);
0419     VMCOREINFO_BUILD_ID();
0420     VMCOREINFO_PAGESIZE(PAGE_SIZE);
0421 
0422     VMCOREINFO_SYMBOL(init_uts_ns);
0423     VMCOREINFO_OFFSET(uts_namespace, name);
0424     VMCOREINFO_SYMBOL(node_online_map);
0425 #ifdef CONFIG_MMU
0426     VMCOREINFO_SYMBOL_ARRAY(swapper_pg_dir);
0427 #endif
0428     VMCOREINFO_SYMBOL(_stext);
0429     VMCOREINFO_SYMBOL(vmap_area_list);
0430 
0431 #ifndef CONFIG_NUMA
0432     VMCOREINFO_SYMBOL(mem_map);
0433     VMCOREINFO_SYMBOL(contig_page_data);
0434 #endif
0435 #ifdef CONFIG_SPARSEMEM
0436     VMCOREINFO_SYMBOL_ARRAY(mem_section);
0437     VMCOREINFO_LENGTH(mem_section, NR_SECTION_ROOTS);
0438     VMCOREINFO_STRUCT_SIZE(mem_section);
0439     VMCOREINFO_OFFSET(mem_section, section_mem_map);
0440     VMCOREINFO_NUMBER(SECTION_SIZE_BITS);
0441     VMCOREINFO_NUMBER(MAX_PHYSMEM_BITS);
0442 #endif
0443     VMCOREINFO_STRUCT_SIZE(page);
0444     VMCOREINFO_STRUCT_SIZE(pglist_data);
0445     VMCOREINFO_STRUCT_SIZE(zone);
0446     VMCOREINFO_STRUCT_SIZE(free_area);
0447     VMCOREINFO_STRUCT_SIZE(list_head);
0448     VMCOREINFO_SIZE(nodemask_t);
0449     VMCOREINFO_OFFSET(page, flags);
0450     VMCOREINFO_OFFSET(page, _refcount);
0451     VMCOREINFO_OFFSET(page, mapping);
0452     VMCOREINFO_OFFSET(page, lru);
0453     VMCOREINFO_OFFSET(page, _mapcount);
0454     VMCOREINFO_OFFSET(page, private);
0455     VMCOREINFO_OFFSET(page, compound_dtor);
0456     VMCOREINFO_OFFSET(page, compound_order);
0457     VMCOREINFO_OFFSET(page, compound_head);
0458     VMCOREINFO_OFFSET(pglist_data, node_zones);
0459     VMCOREINFO_OFFSET(pglist_data, nr_zones);
0460 #ifdef CONFIG_FLATMEM
0461     VMCOREINFO_OFFSET(pglist_data, node_mem_map);
0462 #endif
0463     VMCOREINFO_OFFSET(pglist_data, node_start_pfn);
0464     VMCOREINFO_OFFSET(pglist_data, node_spanned_pages);
0465     VMCOREINFO_OFFSET(pglist_data, node_id);
0466     VMCOREINFO_OFFSET(zone, free_area);
0467     VMCOREINFO_OFFSET(zone, vm_stat);
0468     VMCOREINFO_OFFSET(zone, spanned_pages);
0469     VMCOREINFO_OFFSET(free_area, free_list);
0470     VMCOREINFO_OFFSET(list_head, next);
0471     VMCOREINFO_OFFSET(list_head, prev);
0472     VMCOREINFO_OFFSET(vmap_area, va_start);
0473     VMCOREINFO_OFFSET(vmap_area, list);
0474     VMCOREINFO_LENGTH(zone.free_area, MAX_ORDER);
0475     log_buf_vmcoreinfo_setup();
0476     VMCOREINFO_LENGTH(free_area.free_list, MIGRATE_TYPES);
0477     VMCOREINFO_NUMBER(NR_FREE_PAGES);
0478     VMCOREINFO_NUMBER(PG_lru);
0479     VMCOREINFO_NUMBER(PG_private);
0480     VMCOREINFO_NUMBER(PG_swapcache);
0481     VMCOREINFO_NUMBER(PG_swapbacked);
0482     VMCOREINFO_NUMBER(PG_slab);
0483 #ifdef CONFIG_MEMORY_FAILURE
0484     VMCOREINFO_NUMBER(PG_hwpoison);
0485 #endif
0486     VMCOREINFO_NUMBER(PG_head_mask);
0487 #define PAGE_BUDDY_MAPCOUNT_VALUE   (~PG_buddy)
0488     VMCOREINFO_NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE);
0489 #ifdef CONFIG_HUGETLB_PAGE
0490     VMCOREINFO_NUMBER(HUGETLB_PAGE_DTOR);
0491 #define PAGE_OFFLINE_MAPCOUNT_VALUE (~PG_offline)
0492     VMCOREINFO_NUMBER(PAGE_OFFLINE_MAPCOUNT_VALUE);
0493 #endif
0494 
0495 #ifdef CONFIG_KALLSYMS
0496     VMCOREINFO_SYMBOL(kallsyms_names);
0497     VMCOREINFO_SYMBOL(kallsyms_num_syms);
0498     VMCOREINFO_SYMBOL(kallsyms_token_table);
0499     VMCOREINFO_SYMBOL(kallsyms_token_index);
0500 #ifdef CONFIG_KALLSYMS_BASE_RELATIVE
0501     VMCOREINFO_SYMBOL(kallsyms_offsets);
0502     VMCOREINFO_SYMBOL(kallsyms_relative_base);
0503 #else
0504     VMCOREINFO_SYMBOL(kallsyms_addresses);
0505 #endif /* CONFIG_KALLSYMS_BASE_RELATIVE */
0506 #endif /* CONFIG_KALLSYMS */
0507 
0508     arch_crash_save_vmcoreinfo();
0509     update_vmcoreinfo_note();
0510 
0511     return 0;
0512 }
0513 
0514 subsys_initcall(crash_save_vmcoreinfo_init);