crash_dump.c 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/highmem.h>
  3. #include <linux/bootmem.h>
  4. #include <linux/crash_dump.h>
  5. #include <linux/uaccess.h>
  6. #include <linux/slab.h>
  7. static void *kdump_buf_page;
  8. /**
  9. * copy_oldmem_page - copy one page from "oldmem"
  10. * @pfn: page frame number to be copied
  11. * @buf: target memory address for the copy; this can be in kernel address
  12. * space or user address space (see @userbuf)
  13. * @csize: number of bytes to copy
  14. * @offset: offset in bytes into the page (based on pfn) to begin the copy
  15. * @userbuf: if set, @buf is in user address space, use copy_to_user(),
  16. * otherwise @buf is in kernel address space, use memcpy().
  17. *
  18. * Copy a page from "oldmem". For this page, there is no pte mapped
  19. * in the current kernel.
  20. *
  21. * Calling copy_to_user() in atomic context is not desirable. Hence first
  22. * copying the data to a pre-allocated kernel page and then copying to user
  23. * space in non-atomic context.
  24. */
  25. ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
  26. size_t csize, unsigned long offset, int userbuf)
  27. {
  28. void *vaddr;
  29. if (!csize)
  30. return 0;
  31. vaddr = kmap_atomic_pfn(pfn);
  32. if (!userbuf) {
  33. memcpy(buf, (vaddr + offset), csize);
  34. kunmap_atomic(vaddr);
  35. } else {
  36. if (!kdump_buf_page) {
  37. pr_warn("Kdump: Kdump buffer page not allocated\n");
  38. return -EFAULT;
  39. }
  40. copy_page(kdump_buf_page, vaddr);
  41. kunmap_atomic(vaddr);
  42. if (copy_to_user(buf, (kdump_buf_page + offset), csize))
  43. return -EFAULT;
  44. }
  45. return csize;
  46. }
  47. static int __init kdump_buf_page_init(void)
  48. {
  49. int ret = 0;
  50. kdump_buf_page = kmalloc(PAGE_SIZE, GFP_KERNEL);
  51. if (!kdump_buf_page) {
  52. pr_warn("Kdump: Failed to allocate kdump buffer page\n");
  53. ret = -ENOMEM;
  54. }
  55. return ret;
  56. }
  57. arch_initcall(kdump_buf_page_init);