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