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