1 /* 2 * fs/proc/vmcore.c Interface for accessing the crash 3 * dump from the system's previous life. 4 * Heavily borrowed from fs/proc/kcore.c 5 * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) 6 * Copyright (C) IBM Corporation, 2004. All rights reserved 7 * 8 */ 9 10 #include <linux/mm.h> 11 #include <linux/kcore.h> 12 #include <linux/user.h> 13 #include <linux/elf.h> 14 #include <linux/elfcore.h> 15 #include <linux/export.h> 16 #include <linux/slab.h> 17 #include <linux/highmem.h> 18 #include <linux/printk.h> 19 #include <linux/bootmem.h> 20 #include <linux/init.h> 21 #include <linux/crash_dump.h> 22 #include <linux/list.h> 23 #include <asm/uaccess.h> 24 #include <asm/io.h> 25 #include "internal.h" 26 27 /* List representing chunks of contiguous memory areas and their offsets in 28 * vmcore file. 29 */ 30 static LIST_HEAD(vmcore_list); 31 32 /* Stores the pointer to the buffer containing kernel elf core headers. */ 33 static char *elfcorebuf; 34 static size_t elfcorebuf_sz; 35 36 /* Total size of vmcore file. */ 37 static u64 vmcore_size; 38 39 static struct proc_dir_entry *proc_vmcore = NULL; 40 41 /* 42 * Returns > 0 for RAM pages, 0 for non-RAM pages, < 0 on error 43 * The called function has to take care of module refcounting. 44 */ 45 static int (*oldmem_pfn_is_ram)(unsigned long pfn); 46 47 int register_oldmem_pfn_is_ram(int (*fn)(unsigned long pfn)) 48 { 49 if (oldmem_pfn_is_ram) 50 return -EBUSY; 51 oldmem_pfn_is_ram = fn; 52 return 0; 53 } 54 EXPORT_SYMBOL_GPL(register_oldmem_pfn_is_ram); 55 56 void unregister_oldmem_pfn_is_ram(void) 57 { 58 oldmem_pfn_is_ram = NULL; 59 wmb(); 60 } 61 EXPORT_SYMBOL_GPL(unregister_oldmem_pfn_is_ram); 62 63 static int pfn_is_ram(unsigned long pfn) 64 { 65 int (*fn)(unsigned long pfn); 66 /* pfn is ram unless fn() checks pagetype */ 67 int ret = 1; 68 69 /* 70 * Ask hypervisor if the pfn is really ram. 71 * A ballooned page contains no data and reading from such a page 72 * will cause high load in the hypervisor. 73 */ 74 fn = oldmem_pfn_is_ram; 75 if (fn) 76 ret = fn(pfn); 77 78 return ret; 79 } 80 81 /* Reads a page from the oldmem device from given offset. */ 82 static ssize_t read_from_oldmem(char *buf, size_t count, 83 u64 *ppos, int userbuf) 84 { 85 unsigned long pfn, offset; 86 size_t nr_bytes; 87 ssize_t read = 0, tmp; 88 89 if (!count) 90 return 0; 91 92 offset = (unsigned long)(*ppos % PAGE_SIZE); 93 pfn = (unsigned long)(*ppos / PAGE_SIZE); 94 95 do { 96 if (count > (PAGE_SIZE - offset)) 97 nr_bytes = PAGE_SIZE - offset; 98 else 99 nr_bytes = count; 100 101 /* If pfn is not ram, return zeros for sparse dump files */ 102 if (pfn_is_ram(pfn) == 0) 103 memset(buf, 0, nr_bytes); 104 else { 105 tmp = copy_oldmem_page(pfn, buf, nr_bytes, 106 offset, userbuf); 107 if (tmp < 0) 108 return tmp; 109 } 110 *ppos += nr_bytes; 111 count -= nr_bytes; 112 buf += nr_bytes; 113 read += nr_bytes; 114 ++pfn; 115 offset = 0; 116 } while (count); 117 118 return read; 119 } 120 121 /* Maps vmcore file offset to respective physical address in memroy. */ 122 static u64 map_offset_to_paddr(loff_t offset, struct list_head *vc_list, 123 struct vmcore **m_ptr) 124 { 125 struct vmcore *m; 126 u64 paddr; 127 128 list_for_each_entry(m, vc_list, list) { 129 u64 start, end; 130 start = m->offset; 131 end = m->offset + m->size - 1; 132 if (offset >= start && offset <= end) { 133 paddr = m->paddr + offset - start; 134 *m_ptr = m; 135 return paddr; 136 } 137 } 138 *m_ptr = NULL; 139 return 0; 140 } 141 142 /* Read from the ELF header and then the crash dump. On error, negative value is 143 * returned otherwise number of bytes read are returned. 144 */ 145 static ssize_t read_vmcore(struct file *file, char __user *buffer, 146 size_t buflen, loff_t *fpos) 147 { 148 ssize_t acc = 0, tmp; 149 size_t tsz; 150 u64 start, nr_bytes; 151 struct vmcore *curr_m = NULL; 152 153 if (buflen == 0 || *fpos >= vmcore_size) 154 return 0; 155 156 /* trim buflen to not go beyond EOF */ 157 if (buflen > vmcore_size - *fpos) 158 buflen = vmcore_size - *fpos; 159 160 /* Read ELF core header */ 161 if (*fpos < elfcorebuf_sz) { 162 tsz = elfcorebuf_sz - *fpos; 163 if (buflen < tsz) 164 tsz = buflen; 165 if (copy_to_user(buffer, elfcorebuf + *fpos, tsz)) 166 return -EFAULT; 167 buflen -= tsz; 168 *fpos += tsz; 169 buffer += tsz; 170 acc += tsz; 171 172 /* leave now if filled buffer already */ 173 if (buflen == 0) 174 return acc; 175 } 176 177 start = map_offset_to_paddr(*fpos, &vmcore_list, &curr_m); 178 if (!curr_m) 179 return -EINVAL; 180 181 while (buflen) { 182 tsz = min_t(size_t, buflen, PAGE_SIZE - (start & ~PAGE_MASK)); 183 184 /* Calculate left bytes in current memory segment. */ 185 nr_bytes = (curr_m->size - (start - curr_m->paddr)); 186 if (tsz > nr_bytes) 187 tsz = nr_bytes; 188 189 tmp = read_from_oldmem(buffer, tsz, &start, 1); 190 if (tmp < 0) 191 return tmp; 192 buflen -= tsz; 193 *fpos += tsz; 194 buffer += tsz; 195 acc += tsz; 196 if (start >= (curr_m->paddr + curr_m->size)) { 197 if (curr_m->list.next == &vmcore_list) 198 return acc; /*EOF*/ 199 curr_m = list_entry(curr_m->list.next, 200 struct vmcore, list); 201 start = curr_m->paddr; 202 } 203 } 204 return acc; 205 } 206 207 static const struct file_operations proc_vmcore_operations = { 208 .read = read_vmcore, 209 .llseek = default_llseek, 210 }; 211 212 static struct vmcore* __init get_new_element(void) 213 { 214 return kzalloc(sizeof(struct vmcore), GFP_KERNEL); 215 } 216 217 static u64 __init get_vmcore_size_elf64(char *elfptr) 218 { 219 int i; 220 u64 size; 221 Elf64_Ehdr *ehdr_ptr; 222 Elf64_Phdr *phdr_ptr; 223 224 ehdr_ptr = (Elf64_Ehdr *)elfptr; 225 phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); 226 size = sizeof(Elf64_Ehdr) + ((ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr)); 227 for (i = 0; i < ehdr_ptr->e_phnum; i++) { 228 size += phdr_ptr->p_memsz; 229 phdr_ptr++; 230 } 231 return size; 232 } 233 234 static u64 __init get_vmcore_size_elf32(char *elfptr) 235 { 236 int i; 237 u64 size; 238 Elf32_Ehdr *ehdr_ptr; 239 Elf32_Phdr *phdr_ptr; 240 241 ehdr_ptr = (Elf32_Ehdr *)elfptr; 242 phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); 243 size = sizeof(Elf32_Ehdr) + ((ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr)); 244 for (i = 0; i < ehdr_ptr->e_phnum; i++) { 245 size += phdr_ptr->p_memsz; 246 phdr_ptr++; 247 } 248 return size; 249 } 250 251 /* Merges all the PT_NOTE headers into one. */ 252 static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz, 253 struct list_head *vc_list) 254 { 255 int i, nr_ptnote=0, rc=0; 256 char *tmp; 257 Elf64_Ehdr *ehdr_ptr; 258 Elf64_Phdr phdr, *phdr_ptr; 259 Elf64_Nhdr *nhdr_ptr; 260 u64 phdr_sz = 0, note_off; 261 262 ehdr_ptr = (Elf64_Ehdr *)elfptr; 263 phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); 264 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { 265 int j; 266 void *notes_section; 267 struct vmcore *new; 268 u64 offset, max_sz, sz, real_sz = 0; 269 if (phdr_ptr->p_type != PT_NOTE) 270 continue; 271 nr_ptnote++; 272 max_sz = phdr_ptr->p_memsz; 273 offset = phdr_ptr->p_offset; 274 notes_section = kmalloc(max_sz, GFP_KERNEL); 275 if (!notes_section) 276 return -ENOMEM; 277 rc = read_from_oldmem(notes_section, max_sz, &offset, 0); 278 if (rc < 0) { 279 kfree(notes_section); 280 return rc; 281 } 282 nhdr_ptr = notes_section; 283 for (j = 0; j < max_sz; j += sz) { 284 if (nhdr_ptr->n_namesz == 0) 285 break; 286 sz = sizeof(Elf64_Nhdr) + 287 ((nhdr_ptr->n_namesz + 3) & ~3) + 288 ((nhdr_ptr->n_descsz + 3) & ~3); 289 real_sz += sz; 290 nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz); 291 } 292 293 /* Add this contiguous chunk of notes section to vmcore list.*/ 294 new = get_new_element(); 295 if (!new) { 296 kfree(notes_section); 297 return -ENOMEM; 298 } 299 new->paddr = phdr_ptr->p_offset; 300 new->size = real_sz; 301 list_add_tail(&new->list, vc_list); 302 phdr_sz += real_sz; 303 kfree(notes_section); 304 } 305 306 /* Prepare merged PT_NOTE program header. */ 307 phdr.p_type = PT_NOTE; 308 phdr.p_flags = 0; 309 note_off = sizeof(Elf64_Ehdr) + 310 (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf64_Phdr); 311 phdr.p_offset = note_off; 312 phdr.p_vaddr = phdr.p_paddr = 0; 313 phdr.p_filesz = phdr.p_memsz = phdr_sz; 314 phdr.p_align = 0; 315 316 /* Add merged PT_NOTE program header*/ 317 tmp = elfptr + sizeof(Elf64_Ehdr); 318 memcpy(tmp, &phdr, sizeof(phdr)); 319 tmp += sizeof(phdr); 320 321 /* Remove unwanted PT_NOTE program headers. */ 322 i = (nr_ptnote - 1) * sizeof(Elf64_Phdr); 323 *elfsz = *elfsz - i; 324 memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf64_Ehdr)-sizeof(Elf64_Phdr))); 325 326 /* Modify e_phnum to reflect merged headers. */ 327 ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1; 328 329 return 0; 330 } 331 332 /* Merges all the PT_NOTE headers into one. */ 333 static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz, 334 struct list_head *vc_list) 335 { 336 int i, nr_ptnote=0, rc=0; 337 char *tmp; 338 Elf32_Ehdr *ehdr_ptr; 339 Elf32_Phdr phdr, *phdr_ptr; 340 Elf32_Nhdr *nhdr_ptr; 341 u64 phdr_sz = 0, note_off; 342 343 ehdr_ptr = (Elf32_Ehdr *)elfptr; 344 phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); 345 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { 346 int j; 347 void *notes_section; 348 struct vmcore *new; 349 u64 offset, max_sz, sz, real_sz = 0; 350 if (phdr_ptr->p_type != PT_NOTE) 351 continue; 352 nr_ptnote++; 353 max_sz = phdr_ptr->p_memsz; 354 offset = phdr_ptr->p_offset; 355 notes_section = kmalloc(max_sz, GFP_KERNEL); 356 if (!notes_section) 357 return -ENOMEM; 358 rc = read_from_oldmem(notes_section, max_sz, &offset, 0); 359 if (rc < 0) { 360 kfree(notes_section); 361 return rc; 362 } 363 nhdr_ptr = notes_section; 364 for (j = 0; j < max_sz; j += sz) { 365 if (nhdr_ptr->n_namesz == 0) 366 break; 367 sz = sizeof(Elf32_Nhdr) + 368 ((nhdr_ptr->n_namesz + 3) & ~3) + 369 ((nhdr_ptr->n_descsz + 3) & ~3); 370 real_sz += sz; 371 nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz); 372 } 373 374 /* Add this contiguous chunk of notes section to vmcore list.*/ 375 new = get_new_element(); 376 if (!new) { 377 kfree(notes_section); 378 return -ENOMEM; 379 } 380 new->paddr = phdr_ptr->p_offset; 381 new->size = real_sz; 382 list_add_tail(&new->list, vc_list); 383 phdr_sz += real_sz; 384 kfree(notes_section); 385 } 386 387 /* Prepare merged PT_NOTE program header. */ 388 phdr.p_type = PT_NOTE; 389 phdr.p_flags = 0; 390 note_off = sizeof(Elf32_Ehdr) + 391 (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf32_Phdr); 392 phdr.p_offset = note_off; 393 phdr.p_vaddr = phdr.p_paddr = 0; 394 phdr.p_filesz = phdr.p_memsz = phdr_sz; 395 phdr.p_align = 0; 396 397 /* Add merged PT_NOTE program header*/ 398 tmp = elfptr + sizeof(Elf32_Ehdr); 399 memcpy(tmp, &phdr, sizeof(phdr)); 400 tmp += sizeof(phdr); 401 402 /* Remove unwanted PT_NOTE program headers. */ 403 i = (nr_ptnote - 1) * sizeof(Elf32_Phdr); 404 *elfsz = *elfsz - i; 405 memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf32_Ehdr)-sizeof(Elf32_Phdr))); 406 407 /* Modify e_phnum to reflect merged headers. */ 408 ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1; 409 410 return 0; 411 } 412 413 /* Add memory chunks represented by program headers to vmcore list. Also update 414 * the new offset fields of exported program headers. */ 415 static int __init process_ptload_program_headers_elf64(char *elfptr, 416 size_t elfsz, 417 struct list_head *vc_list) 418 { 419 int i; 420 Elf64_Ehdr *ehdr_ptr; 421 Elf64_Phdr *phdr_ptr; 422 loff_t vmcore_off; 423 struct vmcore *new; 424 425 ehdr_ptr = (Elf64_Ehdr *)elfptr; 426 phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); /* PT_NOTE hdr */ 427 428 /* First program header is PT_NOTE header. */ 429 vmcore_off = sizeof(Elf64_Ehdr) + 430 (ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr) + 431 phdr_ptr->p_memsz; /* Note sections */ 432 433 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { 434 if (phdr_ptr->p_type != PT_LOAD) 435 continue; 436 437 /* Add this contiguous chunk of memory to vmcore list.*/ 438 new = get_new_element(); 439 if (!new) 440 return -ENOMEM; 441 new->paddr = phdr_ptr->p_offset; 442 new->size = phdr_ptr->p_memsz; 443 list_add_tail(&new->list, vc_list); 444 445 /* Update the program header offset. */ 446 phdr_ptr->p_offset = vmcore_off; 447 vmcore_off = vmcore_off + phdr_ptr->p_memsz; 448 } 449 return 0; 450 } 451 452 static int __init process_ptload_program_headers_elf32(char *elfptr, 453 size_t elfsz, 454 struct list_head *vc_list) 455 { 456 int i; 457 Elf32_Ehdr *ehdr_ptr; 458 Elf32_Phdr *phdr_ptr; 459 loff_t vmcore_off; 460 struct vmcore *new; 461 462 ehdr_ptr = (Elf32_Ehdr *)elfptr; 463 phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); /* PT_NOTE hdr */ 464 465 /* First program header is PT_NOTE header. */ 466 vmcore_off = sizeof(Elf32_Ehdr) + 467 (ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr) + 468 phdr_ptr->p_memsz; /* Note sections */ 469 470 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { 471 if (phdr_ptr->p_type != PT_LOAD) 472 continue; 473 474 /* Add this contiguous chunk of memory to vmcore list.*/ 475 new = get_new_element(); 476 if (!new) 477 return -ENOMEM; 478 new->paddr = phdr_ptr->p_offset; 479 new->size = phdr_ptr->p_memsz; 480 list_add_tail(&new->list, vc_list); 481 482 /* Update the program header offset */ 483 phdr_ptr->p_offset = vmcore_off; 484 vmcore_off = vmcore_off + phdr_ptr->p_memsz; 485 } 486 return 0; 487 } 488 489 /* Sets offset fields of vmcore elements. */ 490 static void __init set_vmcore_list_offsets_elf64(char *elfptr, 491 struct list_head *vc_list) 492 { 493 loff_t vmcore_off; 494 Elf64_Ehdr *ehdr_ptr; 495 struct vmcore *m; 496 497 ehdr_ptr = (Elf64_Ehdr *)elfptr; 498 499 /* Skip Elf header and program headers. */ 500 vmcore_off = sizeof(Elf64_Ehdr) + 501 (ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr); 502 503 list_for_each_entry(m, vc_list, list) { 504 m->offset = vmcore_off; 505 vmcore_off += m->size; 506 } 507 } 508 509 /* Sets offset fields of vmcore elements. */ 510 static void __init set_vmcore_list_offsets_elf32(char *elfptr, 511 struct list_head *vc_list) 512 { 513 loff_t vmcore_off; 514 Elf32_Ehdr *ehdr_ptr; 515 struct vmcore *m; 516 517 ehdr_ptr = (Elf32_Ehdr *)elfptr; 518 519 /* Skip Elf header and program headers. */ 520 vmcore_off = sizeof(Elf32_Ehdr) + 521 (ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr); 522 523 list_for_each_entry(m, vc_list, list) { 524 m->offset = vmcore_off; 525 vmcore_off += m->size; 526 } 527 } 528 529 static int __init parse_crash_elf64_headers(void) 530 { 531 int rc=0; 532 Elf64_Ehdr ehdr; 533 u64 addr; 534 535 addr = elfcorehdr_addr; 536 537 /* Read Elf header */ 538 rc = read_from_oldmem((char*)&ehdr, sizeof(Elf64_Ehdr), &addr, 0); 539 if (rc < 0) 540 return rc; 541 542 /* Do some basic Verification. */ 543 if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || 544 (ehdr.e_type != ET_CORE) || 545 !vmcore_elf64_check_arch(&ehdr) || 546 ehdr.e_ident[EI_CLASS] != ELFCLASS64 || 547 ehdr.e_ident[EI_VERSION] != EV_CURRENT || 548 ehdr.e_version != EV_CURRENT || 549 ehdr.e_ehsize != sizeof(Elf64_Ehdr) || 550 ehdr.e_phentsize != sizeof(Elf64_Phdr) || 551 ehdr.e_phnum == 0) { 552 pr_warn("Warning: Core image elf header is not sane\n"); 553 return -EINVAL; 554 } 555 556 /* Read in all elf headers. */ 557 elfcorebuf_sz = sizeof(Elf64_Ehdr) + ehdr.e_phnum * sizeof(Elf64_Phdr); 558 elfcorebuf = kmalloc(elfcorebuf_sz, GFP_KERNEL); 559 if (!elfcorebuf) 560 return -ENOMEM; 561 addr = elfcorehdr_addr; 562 rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz, &addr, 0); 563 if (rc < 0) { 564 kfree(elfcorebuf); 565 return rc; 566 } 567 568 /* Merge all PT_NOTE headers into one. */ 569 rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz, &vmcore_list); 570 if (rc) { 571 kfree(elfcorebuf); 572 return rc; 573 } 574 rc = process_ptload_program_headers_elf64(elfcorebuf, elfcorebuf_sz, 575 &vmcore_list); 576 if (rc) { 577 kfree(elfcorebuf); 578 return rc; 579 } 580 set_vmcore_list_offsets_elf64(elfcorebuf, &vmcore_list); 581 return 0; 582 } 583 584 static int __init parse_crash_elf32_headers(void) 585 { 586 int rc=0; 587 Elf32_Ehdr ehdr; 588 u64 addr; 589 590 addr = elfcorehdr_addr; 591 592 /* Read Elf header */ 593 rc = read_from_oldmem((char*)&ehdr, sizeof(Elf32_Ehdr), &addr, 0); 594 if (rc < 0) 595 return rc; 596 597 /* Do some basic Verification. */ 598 if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || 599 (ehdr.e_type != ET_CORE) || 600 !elf_check_arch(&ehdr) || 601 ehdr.e_ident[EI_CLASS] != ELFCLASS32|| 602 ehdr.e_ident[EI_VERSION] != EV_CURRENT || 603 ehdr.e_version != EV_CURRENT || 604 ehdr.e_ehsize != sizeof(Elf32_Ehdr) || 605 ehdr.e_phentsize != sizeof(Elf32_Phdr) || 606 ehdr.e_phnum == 0) { 607 pr_warn("Warning: Core image elf header is not sane\n"); 608 return -EINVAL; 609 } 610 611 /* Read in all elf headers. */ 612 elfcorebuf_sz = sizeof(Elf32_Ehdr) + ehdr.e_phnum * sizeof(Elf32_Phdr); 613 elfcorebuf = kmalloc(elfcorebuf_sz, GFP_KERNEL); 614 if (!elfcorebuf) 615 return -ENOMEM; 616 addr = elfcorehdr_addr; 617 rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz, &addr, 0); 618 if (rc < 0) { 619 kfree(elfcorebuf); 620 return rc; 621 } 622 623 /* Merge all PT_NOTE headers into one. */ 624 rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz, &vmcore_list); 625 if (rc) { 626 kfree(elfcorebuf); 627 return rc; 628 } 629 rc = process_ptload_program_headers_elf32(elfcorebuf, elfcorebuf_sz, 630 &vmcore_list); 631 if (rc) { 632 kfree(elfcorebuf); 633 return rc; 634 } 635 set_vmcore_list_offsets_elf32(elfcorebuf, &vmcore_list); 636 return 0; 637 } 638 639 static int __init parse_crash_elf_headers(void) 640 { 641 unsigned char e_ident[EI_NIDENT]; 642 u64 addr; 643 int rc=0; 644 645 addr = elfcorehdr_addr; 646 rc = read_from_oldmem(e_ident, EI_NIDENT, &addr, 0); 647 if (rc < 0) 648 return rc; 649 if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) { 650 pr_warn("Warning: Core image elf header not found\n"); 651 return -EINVAL; 652 } 653 654 if (e_ident[EI_CLASS] == ELFCLASS64) { 655 rc = parse_crash_elf64_headers(); 656 if (rc) 657 return rc; 658 659 /* Determine vmcore size. */ 660 vmcore_size = get_vmcore_size_elf64(elfcorebuf); 661 } else if (e_ident[EI_CLASS] == ELFCLASS32) { 662 rc = parse_crash_elf32_headers(); 663 if (rc) 664 return rc; 665 666 /* Determine vmcore size. */ 667 vmcore_size = get_vmcore_size_elf32(elfcorebuf); 668 } else { 669 pr_warn("Warning: Core image elf header is not sane\n"); 670 return -EINVAL; 671 } 672 return 0; 673 } 674 675 /* Init function for vmcore module. */ 676 static int __init vmcore_init(void) 677 { 678 int rc = 0; 679 680 /* If elfcorehdr= has been passed in cmdline, then capture the dump.*/ 681 if (!(is_vmcore_usable())) 682 return rc; 683 rc = parse_crash_elf_headers(); 684 if (rc) { 685 pr_warn("Kdump: vmcore not initialized\n"); 686 return rc; 687 } 688 689 proc_vmcore = proc_create("vmcore", S_IRUSR, NULL, &proc_vmcore_operations); 690 if (proc_vmcore) 691 proc_vmcore->size = vmcore_size; 692 return 0; 693 } 694 module_init(vmcore_init) 695 696 /* Cleanup function for vmcore module. */ 697 void vmcore_cleanup(void) 698 { 699 struct list_head *pos, *next; 700 701 if (proc_vmcore) { 702 proc_remove(proc_vmcore); 703 proc_vmcore = NULL; 704 } 705 706 /* clear the vmcore list. */ 707 list_for_each_safe(pos, next, &vmcore_list) { 708 struct vmcore *m; 709 710 m = list_entry(pos, struct vmcore, list); 711 list_del(&m->list); 712 kfree(m); 713 } 714 kfree(elfcorebuf); 715 elfcorebuf = NULL; 716 } 717 EXPORT_SYMBOL_GPL(vmcore_cleanup); 718