0001
0002
0003
0004
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
0022 unsigned char *vmcoreinfo_data;
0023 size_t vmcoreinfo_size;
0024 u32 *vmcoreinfo_note;
0025
0026
0027 static unsigned char *vmcoreinfo_data_safecopy;
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
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
0053
0054
0055
0056
0057 total_mem = roundup(total_mem, SZ_128M);
0058
0059
0060 do {
0061 unsigned long long start, end = ULLONG_MAX, size;
0062
0063
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
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
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
0133
0134
0135
0136
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
0171
0172
0173
0174
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
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
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
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
0265
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
0278
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
0309
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
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
0390
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
0506 #endif
0507
0508 arch_crash_save_vmcoreinfo();
0509 update_vmcoreinfo_note();
0510
0511 return 0;
0512 }
0513
0514 subsys_initcall(crash_save_vmcoreinfo_init);