linux/arch/x86/kernel/crash_dump_32.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *      Memory preserving reboot related code.
   4 *
   5 *      Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
   6 *      Copyright (C) IBM Corporation, 2004. All rights reserved
   7 */
   8
   9#include <linux/slab.h>
  10#include <linux/errno.h>
  11#include <linux/highmem.h>
  12#include <linux/crash_dump.h>
  13
  14#include <linux/uaccess.h>
  15
  16static inline bool is_crashed_pfn_valid(unsigned long pfn)
  17{
  18#ifndef CONFIG_X86_PAE
  19        /*
  20         * non-PAE kdump kernel executed from a PAE one will crop high pte
  21         * bits and poke unwanted space counting again from address 0, we
  22         * don't want that. pte must fit into unsigned long. In fact the
  23         * test checks high 12 bits for being zero (pfn will be shifted left
  24         * by PAGE_SHIFT).
  25         */
  26        return pte_pfn(pfn_pte(pfn, __pgprot(0))) == pfn;
  27#else
  28        return true;
  29#endif
  30}
  31
  32/**
  33 * copy_oldmem_page - copy one page from "oldmem"
  34 * @pfn: page frame number to be copied
  35 * @buf: target memory address for the copy; this can be in kernel address
  36 *      space or user address space (see @userbuf)
  37 * @csize: number of bytes to copy
  38 * @offset: offset in bytes into the page (based on pfn) to begin the copy
  39 * @userbuf: if set, @buf is in user address space, use copy_to_user(),
  40 *      otherwise @buf is in kernel address space, use memcpy().
  41 *
  42 * Copy a page from "oldmem". For this page, there might be no pte mapped
  43 * in the current kernel.
  44 */
  45ssize_t copy_oldmem_page(unsigned long pfn, char *buf, size_t csize,
  46                         unsigned long offset, int userbuf)
  47{
  48        void  *vaddr;
  49
  50        if (!csize)
  51                return 0;
  52
  53        if (!is_crashed_pfn_valid(pfn))
  54                return -EFAULT;
  55
  56        vaddr = kmap_local_pfn(pfn);
  57
  58        if (!userbuf) {
  59                memcpy(buf, vaddr + offset, csize);
  60        } else {
  61                if (copy_to_user(buf, vaddr + offset, csize))
  62                        csize = -EFAULT;
  63        }
  64
  65        kunmap_local(vaddr);
  66
  67        return csize;
  68}
  69