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