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
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>
27 /* List representing chunks of contiguous memory areas and their offsets in
30 static LIST_HEAD(vmcore_list);
32 /* Stores the pointer to the buffer containing kernel elf core headers. */
33 static char *elfcorebuf;
34 static size_t elfcorebuf_sz;
35 static size_t elfcorebuf_sz_orig;
37 /* Total size of vmcore file. */
38 static u64 vmcore_size;
40 static struct proc_dir_entry *proc_vmcore = NULL;
43 * Returns > 0 for RAM pages, 0 for non-RAM pages, < 0 on error
44 * The called function has to take care of module refcounting.
46 static int (*oldmem_pfn_is_ram)(unsigned long pfn);
48 int register_oldmem_pfn_is_ram(int (*fn)(unsigned long pfn))
50 if (oldmem_pfn_is_ram)
52 oldmem_pfn_is_ram = fn;
55 EXPORT_SYMBOL_GPL(register_oldmem_pfn_is_ram);
57 void unregister_oldmem_pfn_is_ram(void)
59 oldmem_pfn_is_ram = NULL;
62 EXPORT_SYMBOL_GPL(unregister_oldmem_pfn_is_ram);
64 static int pfn_is_ram(unsigned long pfn)
66 int (*fn)(unsigned long pfn);
67 /* pfn is ram unless fn() checks pagetype */
71 * Ask hypervisor if the pfn is really ram.
72 * A ballooned page contains no data and reading from such a page
73 * will cause high load in the hypervisor.
75 fn = oldmem_pfn_is_ram;
82 /* Reads a page from the oldmem device from given offset. */
83 static ssize_t read_from_oldmem(char *buf, size_t count,
84 u64 *ppos, int userbuf)
86 unsigned long pfn, offset;
88 ssize_t read = 0, tmp;
93 offset = (unsigned long)(*ppos % PAGE_SIZE);
94 pfn = (unsigned long)(*ppos / PAGE_SIZE);
97 if (count > (PAGE_SIZE - offset))
98 nr_bytes = PAGE_SIZE - offset;
102 /* If pfn is not ram, return zeros for sparse dump files */
103 if (pfn_is_ram(pfn) == 0)
104 memset(buf, 0, nr_bytes);
106 tmp = copy_oldmem_page(pfn, buf, nr_bytes,
122 /* Read from the ELF header and then the crash dump. On error, negative value is
123 * returned otherwise number of bytes read are returned.
125 static ssize_t read_vmcore(struct file *file, char __user *buffer,
126 size_t buflen, loff_t *fpos)
128 ssize_t acc = 0, tmp;
131 struct vmcore *m = NULL;
133 if (buflen == 0 || *fpos >= vmcore_size)
136 /* trim buflen to not go beyond EOF */
137 if (buflen > vmcore_size - *fpos)
138 buflen = vmcore_size - *fpos;
140 /* Read ELF core header */
141 if (*fpos < elfcorebuf_sz) {
142 tsz = elfcorebuf_sz - *fpos;
145 if (copy_to_user(buffer, elfcorebuf + *fpos, tsz))
152 /* leave now if filled buffer already */
157 list_for_each_entry(m, &vmcore_list, list) {
158 if (*fpos < m->offset + m->size) {
159 tsz = m->offset + m->size - *fpos;
162 start = m->paddr + *fpos - m->offset;
163 tmp = read_from_oldmem(buffer, tsz, &start, 1);
171 /* leave now if filled buffer already */
180 static const struct file_operations proc_vmcore_operations = {
182 .llseek = default_llseek,
185 static struct vmcore* __init get_new_element(void)
187 return kzalloc(sizeof(struct vmcore), GFP_KERNEL);
190 static u64 __init get_vmcore_size_elf64(char *elfptr, size_t elfsz)
194 Elf64_Ehdr *ehdr_ptr;
195 Elf64_Phdr *phdr_ptr;
197 ehdr_ptr = (Elf64_Ehdr *)elfptr;
198 phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr));
200 for (i = 0; i < ehdr_ptr->e_phnum; i++) {
201 size += phdr_ptr->p_memsz;
207 static u64 __init get_vmcore_size_elf32(char *elfptr, size_t elfsz)
211 Elf32_Ehdr *ehdr_ptr;
212 Elf32_Phdr *phdr_ptr;
214 ehdr_ptr = (Elf32_Ehdr *)elfptr;
215 phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr));
217 for (i = 0; i < ehdr_ptr->e_phnum; i++) {
218 size += phdr_ptr->p_memsz;
224 /* Merges all the PT_NOTE headers into one. */
225 static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
226 struct list_head *vc_list)
228 int i, nr_ptnote=0, rc=0;
230 Elf64_Ehdr *ehdr_ptr;
231 Elf64_Phdr phdr, *phdr_ptr;
232 Elf64_Nhdr *nhdr_ptr;
233 u64 phdr_sz = 0, note_off;
235 ehdr_ptr = (Elf64_Ehdr *)elfptr;
236 phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr));
237 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
241 u64 offset, max_sz, sz, real_sz = 0;
242 if (phdr_ptr->p_type != PT_NOTE)
245 max_sz = phdr_ptr->p_memsz;
246 offset = phdr_ptr->p_offset;
247 notes_section = kmalloc(max_sz, GFP_KERNEL);
250 rc = read_from_oldmem(notes_section, max_sz, &offset, 0);
252 kfree(notes_section);
255 nhdr_ptr = notes_section;
256 for (j = 0; j < max_sz; j += sz) {
257 if (nhdr_ptr->n_namesz == 0)
259 sz = sizeof(Elf64_Nhdr) +
260 ((nhdr_ptr->n_namesz + 3) & ~3) +
261 ((nhdr_ptr->n_descsz + 3) & ~3);
263 nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz);
266 /* Add this contiguous chunk of notes section to vmcore list.*/
267 new = get_new_element();
269 kfree(notes_section);
272 new->paddr = phdr_ptr->p_offset;
274 list_add_tail(&new->list, vc_list);
276 kfree(notes_section);
279 /* Prepare merged PT_NOTE program header. */
280 phdr.p_type = PT_NOTE;
282 note_off = sizeof(Elf64_Ehdr) +
283 (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf64_Phdr);
284 phdr.p_offset = note_off;
285 phdr.p_vaddr = phdr.p_paddr = 0;
286 phdr.p_filesz = phdr.p_memsz = phdr_sz;
289 /* Add merged PT_NOTE program header*/
290 tmp = elfptr + sizeof(Elf64_Ehdr);
291 memcpy(tmp, &phdr, sizeof(phdr));
294 /* Remove unwanted PT_NOTE program headers. */
295 i = (nr_ptnote - 1) * sizeof(Elf64_Phdr);
297 memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf64_Ehdr)-sizeof(Elf64_Phdr)));
298 memset(elfptr + *elfsz, 0, i);
299 *elfsz = roundup(*elfsz, PAGE_SIZE);
301 /* Modify e_phnum to reflect merged headers. */
302 ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1;
307 /* Merges all the PT_NOTE headers into one. */
308 static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
309 struct list_head *vc_list)
311 int i, nr_ptnote=0, rc=0;
313 Elf32_Ehdr *ehdr_ptr;
314 Elf32_Phdr phdr, *phdr_ptr;
315 Elf32_Nhdr *nhdr_ptr;
316 u64 phdr_sz = 0, note_off;
318 ehdr_ptr = (Elf32_Ehdr *)elfptr;
319 phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr));
320 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
324 u64 offset, max_sz, sz, real_sz = 0;
325 if (phdr_ptr->p_type != PT_NOTE)
328 max_sz = phdr_ptr->p_memsz;
329 offset = phdr_ptr->p_offset;
330 notes_section = kmalloc(max_sz, GFP_KERNEL);
333 rc = read_from_oldmem(notes_section, max_sz, &offset, 0);
335 kfree(notes_section);
338 nhdr_ptr = notes_section;
339 for (j = 0; j < max_sz; j += sz) {
340 if (nhdr_ptr->n_namesz == 0)
342 sz = sizeof(Elf32_Nhdr) +
343 ((nhdr_ptr->n_namesz + 3) & ~3) +
344 ((nhdr_ptr->n_descsz + 3) & ~3);
346 nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz);
349 /* Add this contiguous chunk of notes section to vmcore list.*/
350 new = get_new_element();
352 kfree(notes_section);
355 new->paddr = phdr_ptr->p_offset;
357 list_add_tail(&new->list, vc_list);
359 kfree(notes_section);
362 /* Prepare merged PT_NOTE program header. */
363 phdr.p_type = PT_NOTE;
365 note_off = sizeof(Elf32_Ehdr) +
366 (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf32_Phdr);
367 phdr.p_offset = note_off;
368 phdr.p_vaddr = phdr.p_paddr = 0;
369 phdr.p_filesz = phdr.p_memsz = phdr_sz;
372 /* Add merged PT_NOTE program header*/
373 tmp = elfptr + sizeof(Elf32_Ehdr);
374 memcpy(tmp, &phdr, sizeof(phdr));
377 /* Remove unwanted PT_NOTE program headers. */
378 i = (nr_ptnote - 1) * sizeof(Elf32_Phdr);
380 memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf32_Ehdr)-sizeof(Elf32_Phdr)));
381 memset(elfptr + *elfsz, 0, i);
382 *elfsz = roundup(*elfsz, PAGE_SIZE);
384 /* Modify e_phnum to reflect merged headers. */
385 ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1;
390 /* Add memory chunks represented by program headers to vmcore list. Also update
391 * the new offset fields of exported program headers. */
392 static int __init process_ptload_program_headers_elf64(char *elfptr,
394 struct list_head *vc_list)
397 Elf64_Ehdr *ehdr_ptr;
398 Elf64_Phdr *phdr_ptr;
402 ehdr_ptr = (Elf64_Ehdr *)elfptr;
403 phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); /* PT_NOTE hdr */
405 /* First program header is PT_NOTE header. */
407 phdr_ptr->p_memsz; /* Note sections */
409 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
410 if (phdr_ptr->p_type != PT_LOAD)
413 /* Add this contiguous chunk of memory to vmcore list.*/
414 new = get_new_element();
417 new->paddr = phdr_ptr->p_offset;
418 new->size = phdr_ptr->p_memsz;
419 list_add_tail(&new->list, vc_list);
421 /* Update the program header offset. */
422 phdr_ptr->p_offset = vmcore_off;
423 vmcore_off = vmcore_off + phdr_ptr->p_memsz;
428 static int __init process_ptload_program_headers_elf32(char *elfptr,
430 struct list_head *vc_list)
433 Elf32_Ehdr *ehdr_ptr;
434 Elf32_Phdr *phdr_ptr;
438 ehdr_ptr = (Elf32_Ehdr *)elfptr;
439 phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); /* PT_NOTE hdr */
441 /* First program header is PT_NOTE header. */
443 phdr_ptr->p_memsz; /* Note sections */
445 for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
446 if (phdr_ptr->p_type != PT_LOAD)
449 /* Add this contiguous chunk of memory to vmcore list.*/
450 new = get_new_element();
453 new->paddr = phdr_ptr->p_offset;
454 new->size = phdr_ptr->p_memsz;
455 list_add_tail(&new->list, vc_list);
457 /* Update the program header offset */
458 phdr_ptr->p_offset = vmcore_off;
459 vmcore_off = vmcore_off + phdr_ptr->p_memsz;
464 /* Sets offset fields of vmcore elements. */
465 static void __init set_vmcore_list_offsets(size_t elfsz,
466 struct list_head *vc_list)
471 /* Skip Elf header and program headers. */
474 list_for_each_entry(m, vc_list, list) {
475 m->offset = vmcore_off;
476 vmcore_off += m->size;
480 static void free_elfcorebuf(void)
482 free_pages((unsigned long)elfcorebuf, get_order(elfcorebuf_sz_orig));
486 static int __init parse_crash_elf64_headers(void)
492 addr = elfcorehdr_addr;
494 /* Read Elf header */
495 rc = read_from_oldmem((char*)&ehdr, sizeof(Elf64_Ehdr), &addr, 0);
499 /* Do some basic Verification. */
500 if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
501 (ehdr.e_type != ET_CORE) ||
502 !vmcore_elf64_check_arch(&ehdr) ||
503 ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
504 ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
505 ehdr.e_version != EV_CURRENT ||
506 ehdr.e_ehsize != sizeof(Elf64_Ehdr) ||
507 ehdr.e_phentsize != sizeof(Elf64_Phdr) ||
509 pr_warn("Warning: Core image elf header is not sane\n");
513 /* Read in all elf headers. */
514 elfcorebuf_sz_orig = sizeof(Elf64_Ehdr) +
515 ehdr.e_phnum * sizeof(Elf64_Phdr);
516 elfcorebuf_sz = elfcorebuf_sz_orig;
517 elfcorebuf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
518 get_order(elfcorebuf_sz_orig));
521 addr = elfcorehdr_addr;
522 rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz_orig, &addr, 0);
526 /* Merge all PT_NOTE headers into one. */
527 rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz, &vmcore_list);
530 rc = process_ptload_program_headers_elf64(elfcorebuf, elfcorebuf_sz,
534 set_vmcore_list_offsets(elfcorebuf_sz, &vmcore_list);
541 static int __init parse_crash_elf32_headers(void)
547 addr = elfcorehdr_addr;
549 /* Read Elf header */
550 rc = read_from_oldmem((char*)&ehdr, sizeof(Elf32_Ehdr), &addr, 0);
554 /* Do some basic Verification. */
555 if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
556 (ehdr.e_type != ET_CORE) ||
557 !elf_check_arch(&ehdr) ||
558 ehdr.e_ident[EI_CLASS] != ELFCLASS32||
559 ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
560 ehdr.e_version != EV_CURRENT ||
561 ehdr.e_ehsize != sizeof(Elf32_Ehdr) ||
562 ehdr.e_phentsize != sizeof(Elf32_Phdr) ||
564 pr_warn("Warning: Core image elf header is not sane\n");
568 /* Read in all elf headers. */
569 elfcorebuf_sz_orig = sizeof(Elf32_Ehdr) + ehdr.e_phnum * sizeof(Elf32_Phdr);
570 elfcorebuf_sz = elfcorebuf_sz_orig;
571 elfcorebuf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
572 get_order(elfcorebuf_sz_orig));
575 addr = elfcorehdr_addr;
576 rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz_orig, &addr, 0);
580 /* Merge all PT_NOTE headers into one. */
581 rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz, &vmcore_list);
584 rc = process_ptload_program_headers_elf32(elfcorebuf, elfcorebuf_sz,
588 set_vmcore_list_offsets(elfcorebuf_sz, &vmcore_list);
595 static int __init parse_crash_elf_headers(void)
597 unsigned char e_ident[EI_NIDENT];
601 addr = elfcorehdr_addr;
602 rc = read_from_oldmem(e_ident, EI_NIDENT, &addr, 0);
605 if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
606 pr_warn("Warning: Core image elf header not found\n");
610 if (e_ident[EI_CLASS] == ELFCLASS64) {
611 rc = parse_crash_elf64_headers();
615 /* Determine vmcore size. */
616 vmcore_size = get_vmcore_size_elf64(elfcorebuf, elfcorebuf_sz);
617 } else if (e_ident[EI_CLASS] == ELFCLASS32) {
618 rc = parse_crash_elf32_headers();
622 /* Determine vmcore size. */
623 vmcore_size = get_vmcore_size_elf32(elfcorebuf, elfcorebuf_sz);
625 pr_warn("Warning: Core image elf header is not sane\n");
631 /* Init function for vmcore module. */
632 static int __init vmcore_init(void)
636 /* If elfcorehdr= has been passed in cmdline, then capture the dump.*/
637 if (!(is_vmcore_usable()))
639 rc = parse_crash_elf_headers();
641 pr_warn("Kdump: vmcore not initialized\n");
645 proc_vmcore = proc_create("vmcore", S_IRUSR, NULL, &proc_vmcore_operations);
647 proc_vmcore->size = vmcore_size;
650 module_init(vmcore_init)
652 /* Cleanup function for vmcore module. */
653 void vmcore_cleanup(void)
655 struct list_head *pos, *next;
658 proc_remove(proc_vmcore);
662 /* clear the vmcore list. */
663 list_for_each_safe(pos, next, &vmcore_list) {
666 m = list_entry(pos, struct vmcore, list);
672 EXPORT_SYMBOL_GPL(vmcore_cleanup);