xref: /linux/arch/x86/kernel/crash_dump_32.c (revision 9a163ed8e0552fdcffe405d2ea7134819a81456e)
1*9a163ed8SThomas Gleixner /*
2*9a163ed8SThomas Gleixner  *	kernel/crash_dump.c - Memory preserving reboot related code.
3*9a163ed8SThomas Gleixner  *
4*9a163ed8SThomas Gleixner  *	Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
5*9a163ed8SThomas Gleixner  *	Copyright (C) IBM Corporation, 2004. All rights reserved
6*9a163ed8SThomas Gleixner  */
7*9a163ed8SThomas Gleixner 
8*9a163ed8SThomas Gleixner #include <linux/errno.h>
9*9a163ed8SThomas Gleixner #include <linux/highmem.h>
10*9a163ed8SThomas Gleixner #include <linux/crash_dump.h>
11*9a163ed8SThomas Gleixner 
12*9a163ed8SThomas Gleixner #include <asm/uaccess.h>
13*9a163ed8SThomas Gleixner 
14*9a163ed8SThomas Gleixner static void *kdump_buf_page;
15*9a163ed8SThomas Gleixner 
16*9a163ed8SThomas Gleixner /**
17*9a163ed8SThomas Gleixner  * copy_oldmem_page - copy one page from "oldmem"
18*9a163ed8SThomas Gleixner  * @pfn: page frame number to be copied
19*9a163ed8SThomas Gleixner  * @buf: target memory address for the copy; this can be in kernel address
20*9a163ed8SThomas Gleixner  *	space or user address space (see @userbuf)
21*9a163ed8SThomas Gleixner  * @csize: number of bytes to copy
22*9a163ed8SThomas Gleixner  * @offset: offset in bytes into the page (based on pfn) to begin the copy
23*9a163ed8SThomas Gleixner  * @userbuf: if set, @buf is in user address space, use copy_to_user(),
24*9a163ed8SThomas Gleixner  *	otherwise @buf is in kernel address space, use memcpy().
25*9a163ed8SThomas Gleixner  *
26*9a163ed8SThomas Gleixner  * Copy a page from "oldmem". For this page, there is no pte mapped
27*9a163ed8SThomas Gleixner  * in the current kernel. We stitch up a pte, similar to kmap_atomic.
28*9a163ed8SThomas Gleixner  *
29*9a163ed8SThomas Gleixner  * Calling copy_to_user() in atomic context is not desirable. Hence first
30*9a163ed8SThomas Gleixner  * copying the data to a pre-allocated kernel page and then copying to user
31*9a163ed8SThomas Gleixner  * space in non-atomic context.
32*9a163ed8SThomas Gleixner  */
33*9a163ed8SThomas Gleixner ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
34*9a163ed8SThomas Gleixner                                size_t csize, unsigned long offset, int userbuf)
35*9a163ed8SThomas Gleixner {
36*9a163ed8SThomas Gleixner 	void  *vaddr;
37*9a163ed8SThomas Gleixner 
38*9a163ed8SThomas Gleixner 	if (!csize)
39*9a163ed8SThomas Gleixner 		return 0;
40*9a163ed8SThomas Gleixner 
41*9a163ed8SThomas Gleixner 	vaddr = kmap_atomic_pfn(pfn, KM_PTE0);
42*9a163ed8SThomas Gleixner 
43*9a163ed8SThomas Gleixner 	if (!userbuf) {
44*9a163ed8SThomas Gleixner 		memcpy(buf, (vaddr + offset), csize);
45*9a163ed8SThomas Gleixner 		kunmap_atomic(vaddr, KM_PTE0);
46*9a163ed8SThomas Gleixner 	} else {
47*9a163ed8SThomas Gleixner 		if (!kdump_buf_page) {
48*9a163ed8SThomas Gleixner 			printk(KERN_WARNING "Kdump: Kdump buffer page not"
49*9a163ed8SThomas Gleixner 				" allocated\n");
50*9a163ed8SThomas Gleixner 			return -EFAULT;
51*9a163ed8SThomas Gleixner 		}
52*9a163ed8SThomas Gleixner 		copy_page(kdump_buf_page, vaddr);
53*9a163ed8SThomas Gleixner 		kunmap_atomic(vaddr, KM_PTE0);
54*9a163ed8SThomas Gleixner 		if (copy_to_user(buf, (kdump_buf_page + offset), csize))
55*9a163ed8SThomas Gleixner 			return -EFAULT;
56*9a163ed8SThomas Gleixner 	}
57*9a163ed8SThomas Gleixner 
58*9a163ed8SThomas Gleixner 	return csize;
59*9a163ed8SThomas Gleixner }
60*9a163ed8SThomas Gleixner 
61*9a163ed8SThomas Gleixner static int __init kdump_buf_page_init(void)
62*9a163ed8SThomas Gleixner {
63*9a163ed8SThomas Gleixner 	int ret = 0;
64*9a163ed8SThomas Gleixner 
65*9a163ed8SThomas Gleixner 	kdump_buf_page = kmalloc(PAGE_SIZE, GFP_KERNEL);
66*9a163ed8SThomas Gleixner 	if (!kdump_buf_page) {
67*9a163ed8SThomas Gleixner 		printk(KERN_WARNING "Kdump: Failed to allocate kdump buffer"
68*9a163ed8SThomas Gleixner 			 " page\n");
69*9a163ed8SThomas Gleixner 		ret = -ENOMEM;
70*9a163ed8SThomas Gleixner 	}
71*9a163ed8SThomas Gleixner 
72*9a163ed8SThomas Gleixner 	return ret;
73*9a163ed8SThomas Gleixner }
74*9a163ed8SThomas Gleixner arch_initcall(kdump_buf_page_init);
75