LCOV - code coverage report
Current view: top level - fs/proc - vmcore.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 7 548 1.3 %
Date: 2022-03-28 13:20:08 Functions: 2 33 6.1 %
Branches: 2 244 0.8 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  *      fs/proc/vmcore.c Interface for accessing the crash
       4                 :            :  *                               dump from the system's previous life.
       5                 :            :  *      Heavily borrowed from fs/proc/kcore.c
       6                 :            :  *      Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
       7                 :            :  *      Copyright (C) IBM Corporation, 2004. All rights reserved
       8                 :            :  *
       9                 :            :  */
      10                 :            : 
      11                 :            : #include <linux/mm.h>
      12                 :            : #include <linux/kcore.h>
      13                 :            : #include <linux/user.h>
      14                 :            : #include <linux/elf.h>
      15                 :            : #include <linux/elfcore.h>
      16                 :            : #include <linux/export.h>
      17                 :            : #include <linux/slab.h>
      18                 :            : #include <linux/highmem.h>
      19                 :            : #include <linux/printk.h>
      20                 :            : #include <linux/memblock.h>
      21                 :            : #include <linux/init.h>
      22                 :            : #include <linux/crash_dump.h>
      23                 :            : #include <linux/list.h>
      24                 :            : #include <linux/moduleparam.h>
      25                 :            : #include <linux/mutex.h>
      26                 :            : #include <linux/vmalloc.h>
      27                 :            : #include <linux/pagemap.h>
      28                 :            : #include <linux/uaccess.h>
      29                 :            : #include <linux/mem_encrypt.h>
      30                 :            : #include <asm/pgtable.h>
      31                 :            : #include <asm/io.h>
      32                 :            : #include "internal.h"
      33                 :            : 
      34                 :            : /* List representing chunks of contiguous memory areas and their offsets in
      35                 :            :  * vmcore file.
      36                 :            :  */
      37                 :            : static LIST_HEAD(vmcore_list);
      38                 :            : 
      39                 :            : /* Stores the pointer to the buffer containing kernel elf core headers. */
      40                 :            : static char *elfcorebuf;
      41                 :            : static size_t elfcorebuf_sz;
      42                 :            : static size_t elfcorebuf_sz_orig;
      43                 :            : 
      44                 :            : static char *elfnotes_buf;
      45                 :            : static size_t elfnotes_sz;
      46                 :            : /* Size of all notes minus the device dump notes */
      47                 :            : static size_t elfnotes_orig_sz;
      48                 :            : 
      49                 :            : /* Total size of vmcore file. */
      50                 :            : static u64 vmcore_size;
      51                 :            : 
      52                 :            : static struct proc_dir_entry *proc_vmcore;
      53                 :            : 
      54                 :            : #ifdef CONFIG_PROC_VMCORE_DEVICE_DUMP
      55                 :            : /* Device Dump list and mutex to synchronize access to list */
      56                 :            : static LIST_HEAD(vmcoredd_list);
      57                 :            : static DEFINE_MUTEX(vmcoredd_mutex);
      58                 :            : 
      59                 :            : static bool vmcoredd_disabled;
      60                 :            : core_param(novmcoredd, vmcoredd_disabled, bool, 0);
      61                 :            : #endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
      62                 :            : 
      63                 :            : /* Device Dump Size */
      64                 :            : static size_t vmcoredd_orig_sz;
      65                 :            : 
      66                 :            : /*
      67                 :            :  * Returns > 0 for RAM pages, 0 for non-RAM pages, < 0 on error
      68                 :            :  * The called function has to take care of module refcounting.
      69                 :            :  */
      70                 :            : static int (*oldmem_pfn_is_ram)(unsigned long pfn);
      71                 :            : 
      72                 :          0 : int register_oldmem_pfn_is_ram(int (*fn)(unsigned long pfn))
      73                 :            : {
      74         [ #  # ]:          0 :         if (oldmem_pfn_is_ram)
      75                 :            :                 return -EBUSY;
      76                 :          0 :         oldmem_pfn_is_ram = fn;
      77                 :          0 :         return 0;
      78                 :            : }
      79                 :            : EXPORT_SYMBOL_GPL(register_oldmem_pfn_is_ram);
      80                 :            : 
      81                 :          0 : void unregister_oldmem_pfn_is_ram(void)
      82                 :            : {
      83                 :          0 :         oldmem_pfn_is_ram = NULL;
      84                 :          0 :         wmb();
      85                 :          0 : }
      86                 :            : EXPORT_SYMBOL_GPL(unregister_oldmem_pfn_is_ram);
      87                 :            : 
      88                 :          0 : static int pfn_is_ram(unsigned long pfn)
      89                 :            : {
      90                 :          0 :         int (*fn)(unsigned long pfn);
      91                 :            :         /* pfn is ram unless fn() checks pagetype */
      92                 :          0 :         int ret = 1;
      93                 :            : 
      94                 :            :         /*
      95                 :            :          * Ask hypervisor if the pfn is really ram.
      96                 :            :          * A ballooned page contains no data and reading from such a page
      97                 :            :          * will cause high load in the hypervisor.
      98                 :            :          */
      99                 :          0 :         fn = oldmem_pfn_is_ram;
     100                 :          0 :         if (fn)
     101                 :          0 :                 ret = fn(pfn);
     102                 :            : 
     103                 :          0 :         return ret;
     104                 :            : }
     105                 :            : 
     106                 :            : /* Reads a page from the oldmem device from given offset. */
     107                 :          0 : ssize_t read_from_oldmem(char *buf, size_t count,
     108                 :            :                          u64 *ppos, int userbuf,
     109                 :            :                          bool encrypted)
     110                 :            : {
     111                 :          0 :         unsigned long pfn, offset;
     112                 :          0 :         size_t nr_bytes;
     113                 :          0 :         ssize_t read = 0, tmp;
     114                 :            : 
     115         [ #  # ]:          0 :         if (!count)
     116                 :            :                 return 0;
     117                 :            : 
     118                 :          0 :         offset = (unsigned long)(*ppos % PAGE_SIZE);
     119                 :          0 :         pfn = (unsigned long)(*ppos / PAGE_SIZE);
     120                 :            : 
     121                 :          0 :         do {
     122                 :          0 :                 if (count > (PAGE_SIZE - offset))
     123                 :            :                         nr_bytes = PAGE_SIZE - offset;
     124                 :            :                 else
     125                 :            :                         nr_bytes = count;
     126                 :            : 
     127                 :            :                 /* If pfn is not ram, return zeros for sparse dump files */
     128   [ #  #  #  # ]:          0 :                 if (pfn_is_ram(pfn) == 0)
     129                 :          0 :                         memset(buf, 0, nr_bytes);
     130                 :            :                 else {
     131         [ #  # ]:          0 :                         if (encrypted)
     132                 :          0 :                                 tmp = copy_oldmem_page_encrypted(pfn, buf,
     133                 :            :                                                                  nr_bytes,
     134                 :            :                                                                  offset,
     135                 :            :                                                                  userbuf);
     136                 :            :                         else
     137                 :          0 :                                 tmp = copy_oldmem_page(pfn, buf, nr_bytes,
     138                 :            :                                                        offset, userbuf);
     139                 :            : 
     140         [ #  # ]:          0 :                         if (tmp < 0)
     141                 :          0 :                                 return tmp;
     142                 :            :                 }
     143                 :          0 :                 *ppos += nr_bytes;
     144                 :          0 :                 count -= nr_bytes;
     145                 :          0 :                 buf += nr_bytes;
     146                 :          0 :                 read += nr_bytes;
     147                 :          0 :                 ++pfn;
     148                 :          0 :                 offset = 0;
     149         [ #  # ]:          0 :         } while (count);
     150                 :            : 
     151                 :            :         return read;
     152                 :            : }
     153                 :            : 
     154                 :            : /*
     155                 :            :  * Architectures may override this function to allocate ELF header in 2nd kernel
     156                 :            :  */
     157                 :         30 : int __weak elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
     158                 :            : {
     159                 :         30 :         return 0;
     160                 :            : }
     161                 :            : 
     162                 :            : /*
     163                 :            :  * Architectures may override this function to free header
     164                 :            :  */
     165                 :          0 : void __weak elfcorehdr_free(unsigned long long addr)
     166                 :          0 : {}
     167                 :            : 
     168                 :            : /*
     169                 :            :  * Architectures may override this function to read from ELF header
     170                 :            :  */
     171                 :          0 : ssize_t __weak elfcorehdr_read(char *buf, size_t count, u64 *ppos)
     172                 :            : {
     173                 :          0 :         return read_from_oldmem(buf, count, ppos, 0, false);
     174                 :            : }
     175                 :            : 
     176                 :            : /*
     177                 :            :  * Architectures may override this function to read from notes sections
     178                 :            :  */
     179                 :          0 : ssize_t __weak elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos)
     180                 :            : {
     181                 :          0 :         return read_from_oldmem(buf, count, ppos, 0, mem_encrypt_active());
     182                 :            : }
     183                 :            : 
     184                 :            : /*
     185                 :            :  * Architectures may override this function to map oldmem
     186                 :            :  */
     187                 :          0 : int __weak remap_oldmem_pfn_range(struct vm_area_struct *vma,
     188                 :            :                                   unsigned long from, unsigned long pfn,
     189                 :            :                                   unsigned long size, pgprot_t prot)
     190                 :            : {
     191                 :          0 :         prot = pgprot_encrypted(prot);
     192                 :          0 :         return remap_pfn_range(vma, from, pfn, size, prot);
     193                 :            : }
     194                 :            : 
     195                 :            : /*
     196                 :            :  * Architectures which support memory encryption override this.
     197                 :            :  */
     198                 :            : ssize_t __weak
     199                 :          0 : copy_oldmem_page_encrypted(unsigned long pfn, char *buf, size_t csize,
     200                 :            :                            unsigned long offset, int userbuf)
     201                 :            : {
     202                 :          0 :         return copy_oldmem_page(pfn, buf, csize, offset, userbuf);
     203                 :            : }
     204                 :            : 
     205                 :            : /*
     206                 :            :  * Copy to either kernel or user space
     207                 :            :  */
     208                 :          0 : static int copy_to(void *target, void *src, size_t size, int userbuf)
     209                 :            : {
     210         [ #  # ]:          0 :         if (userbuf) {
     211   [ #  #  #  # ]:          0 :                 if (copy_to_user((char __user *) target, src, size))
     212                 :          0 :                         return -EFAULT;
     213                 :            :         } else {
     214                 :          0 :                 memcpy(target, src, size);
     215                 :            :         }
     216                 :            :         return 0;
     217                 :            : }
     218                 :            : 
     219                 :            : #ifdef CONFIG_PROC_VMCORE_DEVICE_DUMP
     220                 :            : static int vmcoredd_copy_dumps(void *dst, u64 start, size_t size, int userbuf)
     221                 :            : {
     222                 :            :         struct vmcoredd_node *dump;
     223                 :            :         u64 offset = 0;
     224                 :            :         int ret = 0;
     225                 :            :         size_t tsz;
     226                 :            :         char *buf;
     227                 :            : 
     228                 :            :         mutex_lock(&vmcoredd_mutex);
     229                 :            :         list_for_each_entry(dump, &vmcoredd_list, list) {
     230                 :            :                 if (start < offset + dump->size) {
     231                 :            :                         tsz = min(offset + (u64)dump->size - start, (u64)size);
     232                 :            :                         buf = dump->buf + start - offset;
     233                 :            :                         if (copy_to(dst, buf, tsz, userbuf)) {
     234                 :            :                                 ret = -EFAULT;
     235                 :            :                                 goto out_unlock;
     236                 :            :                         }
     237                 :            : 
     238                 :            :                         size -= tsz;
     239                 :            :                         start += tsz;
     240                 :            :                         dst += tsz;
     241                 :            : 
     242                 :            :                         /* Leave now if buffer filled already */
     243                 :            :                         if (!size)
     244                 :            :                                 goto out_unlock;
     245                 :            :                 }
     246                 :            :                 offset += dump->size;
     247                 :            :         }
     248                 :            : 
     249                 :            : out_unlock:
     250                 :            :         mutex_unlock(&vmcoredd_mutex);
     251                 :            :         return ret;
     252                 :            : }
     253                 :            : 
     254                 :            : #ifdef CONFIG_MMU
     255                 :            : static int vmcoredd_mmap_dumps(struct vm_area_struct *vma, unsigned long dst,
     256                 :            :                                u64 start, size_t size)
     257                 :            : {
     258                 :            :         struct vmcoredd_node *dump;
     259                 :            :         u64 offset = 0;
     260                 :            :         int ret = 0;
     261                 :            :         size_t tsz;
     262                 :            :         char *buf;
     263                 :            : 
     264                 :            :         mutex_lock(&vmcoredd_mutex);
     265                 :            :         list_for_each_entry(dump, &vmcoredd_list, list) {
     266                 :            :                 if (start < offset + dump->size) {
     267                 :            :                         tsz = min(offset + (u64)dump->size - start, (u64)size);
     268                 :            :                         buf = dump->buf + start - offset;
     269                 :            :                         if (remap_vmalloc_range_partial(vma, dst, buf, tsz)) {
     270                 :            :                                 ret = -EFAULT;
     271                 :            :                                 goto out_unlock;
     272                 :            :                         }
     273                 :            : 
     274                 :            :                         size -= tsz;
     275                 :            :                         start += tsz;
     276                 :            :                         dst += tsz;
     277                 :            : 
     278                 :            :                         /* Leave now if buffer filled already */
     279                 :            :                         if (!size)
     280                 :            :                                 goto out_unlock;
     281                 :            :                 }
     282                 :            :                 offset += dump->size;
     283                 :            :         }
     284                 :            : 
     285                 :            : out_unlock:
     286                 :            :         mutex_unlock(&vmcoredd_mutex);
     287                 :            :         return ret;
     288                 :            : }
     289                 :            : #endif /* CONFIG_MMU */
     290                 :            : #endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
     291                 :            : 
     292                 :            : /* Read from the ELF header and then the crash dump. On error, negative value is
     293                 :            :  * returned otherwise number of bytes read are returned.
     294                 :            :  */
     295                 :          0 : static ssize_t __read_vmcore(char *buffer, size_t buflen, loff_t *fpos,
     296                 :            :                              int userbuf)
     297                 :            : {
     298                 :          0 :         ssize_t acc = 0, tmp;
     299                 :          0 :         size_t tsz;
     300                 :          0 :         u64 start;
     301                 :          0 :         struct vmcore *m = NULL;
     302                 :            : 
     303   [ #  #  #  # ]:          0 :         if (buflen == 0 || *fpos >= vmcore_size)
     304                 :            :                 return 0;
     305                 :            : 
     306                 :            :         /* trim buflen to not go beyond EOF */
     307                 :          0 :         if (buflen > vmcore_size - *fpos)
     308                 :            :                 buflen = vmcore_size - *fpos;
     309                 :            : 
     310                 :            :         /* Read ELF core header */
     311         [ #  # ]:          0 :         if (*fpos < elfcorebuf_sz) {
     312                 :          0 :                 tsz = min(elfcorebuf_sz - (size_t)*fpos, buflen);
     313         [ #  # ]:          0 :                 if (copy_to(buffer, elfcorebuf + *fpos, tsz, userbuf))
     314                 :            :                         return -EFAULT;
     315                 :          0 :                 buflen -= tsz;
     316                 :          0 :                 *fpos += tsz;
     317                 :          0 :                 buffer += tsz;
     318                 :          0 :                 acc += tsz;
     319                 :            : 
     320                 :            :                 /* leave now if filled buffer already */
     321         [ #  # ]:          0 :                 if (buflen == 0)
     322                 :            :                         return acc;
     323                 :            :         }
     324                 :            : 
     325                 :            :         /* Read Elf note segment */
     326         [ #  # ]:          0 :         if (*fpos < elfcorebuf_sz + elfnotes_sz) {
     327                 :          0 :                 void *kaddr;
     328                 :            : 
     329                 :            :                 /* We add device dumps before other elf notes because the
     330                 :            :                  * other elf notes may not fill the elf notes buffer
     331                 :            :                  * completely and we will end up with zero-filled data
     332                 :            :                  * between the elf notes and the device dumps. Tools will
     333                 :            :                  * then try to decode this zero-filled data as valid notes
     334                 :            :                  * and we don't want that. Hence, adding device dumps before
     335                 :            :                  * the other elf notes ensure that zero-filled data can be
     336                 :            :                  * avoided.
     337                 :            :                  */
     338                 :            : #ifdef CONFIG_PROC_VMCORE_DEVICE_DUMP
     339                 :            :                 /* Read device dumps */
     340                 :            :                 if (*fpos < elfcorebuf_sz + vmcoredd_orig_sz) {
     341                 :            :                         tsz = min(elfcorebuf_sz + vmcoredd_orig_sz -
     342                 :            :                                   (size_t)*fpos, buflen);
     343                 :            :                         start = *fpos - elfcorebuf_sz;
     344                 :            :                         if (vmcoredd_copy_dumps(buffer, start, tsz, userbuf))
     345                 :            :                                 return -EFAULT;
     346                 :            : 
     347                 :            :                         buflen -= tsz;
     348                 :            :                         *fpos += tsz;
     349                 :            :                         buffer += tsz;
     350                 :            :                         acc += tsz;
     351                 :            : 
     352                 :            :                         /* leave now if filled buffer already */
     353                 :            :                         if (!buflen)
     354                 :            :                                 return acc;
     355                 :            :                 }
     356                 :            : #endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
     357                 :            : 
     358                 :            :                 /* Read remaining elf notes */
     359                 :          0 :                 tsz = min(elfcorebuf_sz + elfnotes_sz - (size_t)*fpos, buflen);
     360                 :          0 :                 kaddr = elfnotes_buf + *fpos - elfcorebuf_sz - vmcoredd_orig_sz;
     361         [ #  # ]:          0 :                 if (copy_to(buffer, kaddr, tsz, userbuf))
     362                 :            :                         return -EFAULT;
     363                 :            : 
     364                 :          0 :                 buflen -= tsz;
     365                 :          0 :                 *fpos += tsz;
     366                 :          0 :                 buffer += tsz;
     367                 :          0 :                 acc += tsz;
     368                 :            : 
     369                 :            :                 /* leave now if filled buffer already */
     370         [ #  # ]:          0 :                 if (buflen == 0)
     371                 :            :                         return acc;
     372                 :            :         }
     373                 :            : 
     374         [ #  # ]:          0 :         list_for_each_entry(m, &vmcore_list, list) {
     375         [ #  # ]:          0 :                 if (*fpos < m->offset + m->size) {
     376                 :          0 :                         tsz = (size_t)min_t(unsigned long long,
     377                 :            :                                             m->offset + m->size - *fpos,
     378                 :            :                                             buflen);
     379                 :          0 :                         start = m->paddr + *fpos - m->offset;
     380                 :          0 :                         tmp = read_from_oldmem(buffer, tsz, &start,
     381                 :            :                                                userbuf, mem_encrypt_active());
     382         [ #  # ]:          0 :                         if (tmp < 0)
     383                 :          0 :                                 return tmp;
     384                 :          0 :                         buflen -= tsz;
     385                 :          0 :                         *fpos += tsz;
     386                 :          0 :                         buffer += tsz;
     387                 :          0 :                         acc += tsz;
     388                 :            : 
     389                 :            :                         /* leave now if filled buffer already */
     390         [ #  # ]:          0 :                         if (buflen == 0)
     391                 :          0 :                                 return acc;
     392                 :            :                 }
     393                 :            :         }
     394                 :            : 
     395                 :            :         return acc;
     396                 :            : }
     397                 :            : 
     398                 :          0 : static ssize_t read_vmcore(struct file *file, char __user *buffer,
     399                 :            :                            size_t buflen, loff_t *fpos)
     400                 :            : {
     401                 :          0 :         return __read_vmcore((__force char *) buffer, buflen, fpos, 1);
     402                 :            : }
     403                 :            : 
     404                 :            : /*
     405                 :            :  * The vmcore fault handler uses the page cache and fills data using the
     406                 :            :  * standard __vmcore_read() function.
     407                 :            :  *
     408                 :            :  * On s390 the fault handler is used for memory regions that can't be mapped
     409                 :            :  * directly with remap_pfn_range().
     410                 :            :  */
     411                 :          0 : static vm_fault_t mmap_vmcore_fault(struct vm_fault *vmf)
     412                 :            : {
     413                 :            : #ifdef CONFIG_S390
     414                 :            :         struct address_space *mapping = vmf->vma->vm_file->f_mapping;
     415                 :            :         pgoff_t index = vmf->pgoff;
     416                 :            :         struct page *page;
     417                 :            :         loff_t offset;
     418                 :            :         char *buf;
     419                 :            :         int rc;
     420                 :            : 
     421                 :            :         page = find_or_create_page(mapping, index, GFP_KERNEL);
     422                 :            :         if (!page)
     423                 :            :                 return VM_FAULT_OOM;
     424                 :            :         if (!PageUptodate(page)) {
     425                 :            :                 offset = (loff_t) index << PAGE_SHIFT;
     426                 :            :                 buf = __va((page_to_pfn(page) << PAGE_SHIFT));
     427                 :            :                 rc = __read_vmcore(buf, PAGE_SIZE, &offset, 0);
     428                 :            :                 if (rc < 0) {
     429                 :            :                         unlock_page(page);
     430                 :            :                         put_page(page);
     431                 :            :                         return vmf_error(rc);
     432                 :            :                 }
     433                 :            :                 SetPageUptodate(page);
     434                 :            :         }
     435                 :            :         unlock_page(page);
     436                 :            :         vmf->page = page;
     437                 :            :         return 0;
     438                 :            : #else
     439                 :          0 :         return VM_FAULT_SIGBUS;
     440                 :            : #endif
     441                 :            : }
     442                 :            : 
     443                 :            : static const struct vm_operations_struct vmcore_mmap_ops = {
     444                 :            :         .fault = mmap_vmcore_fault,
     445                 :            : };
     446                 :            : 
     447                 :            : /**
     448                 :            :  * vmcore_alloc_buf - allocate buffer in vmalloc memory
     449                 :            :  * @sizez: size of buffer
     450                 :            :  *
     451                 :            :  * If CONFIG_MMU is defined, use vmalloc_user() to allow users to mmap
     452                 :            :  * the buffer to user-space by means of remap_vmalloc_range().
     453                 :            :  *
     454                 :            :  * If CONFIG_MMU is not defined, use vzalloc() since mmap_vmcore() is
     455                 :            :  * disabled and there's no need to allow users to mmap the buffer.
     456                 :            :  */
     457                 :          0 : static inline char *vmcore_alloc_buf(size_t size)
     458                 :            : {
     459                 :            : #ifdef CONFIG_MMU
     460                 :          0 :         return vmalloc_user(size);
     461                 :            : #else
     462                 :            :         return vzalloc(size);
     463                 :            : #endif
     464                 :            : }
     465                 :            : 
     466                 :            : /*
     467                 :            :  * Disable mmap_vmcore() if CONFIG_MMU is not defined. MMU is
     468                 :            :  * essential for mmap_vmcore() in order to map physically
     469                 :            :  * non-contiguous objects (ELF header, ELF note segment and memory
     470                 :            :  * regions in the 1st kernel pointed to by PT_LOAD entries) into
     471                 :            :  * virtually contiguous user-space in ELF layout.
     472                 :            :  */
     473                 :            : #ifdef CONFIG_MMU
     474                 :            : /*
     475                 :            :  * remap_oldmem_pfn_checked - do remap_oldmem_pfn_range replacing all pages
     476                 :            :  * reported as not being ram with the zero page.
     477                 :            :  *
     478                 :            :  * @vma: vm_area_struct describing requested mapping
     479                 :            :  * @from: start remapping from
     480                 :            :  * @pfn: page frame number to start remapping to
     481                 :            :  * @size: remapping size
     482                 :            :  * @prot: protection bits
     483                 :            :  *
     484                 :            :  * Returns zero on success, -EAGAIN on failure.
     485                 :            :  */
     486                 :          0 : static int remap_oldmem_pfn_checked(struct vm_area_struct *vma,
     487                 :            :                                     unsigned long from, unsigned long pfn,
     488                 :            :                                     unsigned long size, pgprot_t prot)
     489                 :            : {
     490                 :          0 :         unsigned long map_size;
     491                 :          0 :         unsigned long pos_start, pos_end, pos;
     492                 :          0 :         unsigned long zeropage_pfn = my_zero_pfn(0);
     493                 :          0 :         size_t len = 0;
     494                 :            : 
     495                 :          0 :         pos_start = pfn;
     496                 :          0 :         pos_end = pfn + (size >> PAGE_SHIFT);
     497                 :            : 
     498         [ #  # ]:          0 :         for (pos = pos_start; pos < pos_end; ++pos) {
     499   [ #  #  #  # ]:          0 :                 if (!pfn_is_ram(pos)) {
     500                 :            :                         /*
     501                 :            :                          * We hit a page which is not ram. Remap the continuous
     502                 :            :                          * region between pos_start and pos-1 and replace
     503                 :            :                          * the non-ram page at pos with the zero page.
     504                 :            :                          */
     505         [ #  # ]:          0 :                         if (pos > pos_start) {
     506                 :            :                                 /* Remap continuous region */
     507                 :          0 :                                 map_size = (pos - pos_start) << PAGE_SHIFT;
     508         [ #  # ]:          0 :                                 if (remap_oldmem_pfn_range(vma, from + len,
     509                 :            :                                                            pos_start, map_size,
     510                 :            :                                                            prot))
     511                 :          0 :                                         goto fail;
     512                 :          0 :                                 len += map_size;
     513                 :            :                         }
     514                 :            :                         /* Remap the zero page */
     515         [ #  # ]:          0 :                         if (remap_oldmem_pfn_range(vma, from + len,
     516                 :            :                                                    zeropage_pfn,
     517                 :            :                                                    PAGE_SIZE, prot))
     518                 :          0 :                                 goto fail;
     519                 :          0 :                         len += PAGE_SIZE;
     520                 :          0 :                         pos_start = pos + 1;
     521                 :            :                 }
     522                 :            :         }
     523         [ #  # ]:          0 :         if (pos > pos_start) {
     524                 :            :                 /* Remap the rest */
     525                 :          0 :                 map_size = (pos - pos_start) << PAGE_SHIFT;
     526         [ #  # ]:          0 :                 if (remap_oldmem_pfn_range(vma, from + len, pos_start,
     527                 :            :                                            map_size, prot))
     528                 :          0 :                         goto fail;
     529                 :            :         }
     530                 :            :         return 0;
     531                 :          0 : fail:
     532                 :          0 :         do_munmap(vma->vm_mm, from, len, NULL);
     533                 :          0 :         return -EAGAIN;
     534                 :            : }
     535                 :            : 
     536                 :          0 : static int vmcore_remap_oldmem_pfn(struct vm_area_struct *vma,
     537                 :            :                             unsigned long from, unsigned long pfn,
     538                 :            :                             unsigned long size, pgprot_t prot)
     539                 :            : {
     540                 :            :         /*
     541                 :            :          * Check if oldmem_pfn_is_ram was registered to avoid
     542                 :            :          * looping over all pages without a reason.
     543                 :            :          */
     544         [ #  # ]:          0 :         if (oldmem_pfn_is_ram)
     545                 :          0 :                 return remap_oldmem_pfn_checked(vma, from, pfn, size, prot);
     546                 :            :         else
     547                 :          0 :                 return remap_oldmem_pfn_range(vma, from, pfn, size, prot);
     548                 :            : }
     549                 :            : 
     550                 :          0 : static int mmap_vmcore(struct file *file, struct vm_area_struct *vma)
     551                 :            : {
     552                 :          0 :         size_t size = vma->vm_end - vma->vm_start;
     553                 :          0 :         u64 start, end, len, tsz;
     554                 :          0 :         struct vmcore *m;
     555                 :            : 
     556                 :          0 :         start = (u64)vma->vm_pgoff << PAGE_SHIFT;
     557                 :          0 :         end = start + size;
     558                 :            : 
     559   [ #  #  #  # ]:          0 :         if (size > vmcore_size || end > vmcore_size)
     560                 :            :                 return -EINVAL;
     561                 :            : 
     562         [ #  # ]:          0 :         if (vma->vm_flags & (VM_WRITE | VM_EXEC))
     563                 :            :                 return -EPERM;
     564                 :            : 
     565                 :          0 :         vma->vm_flags &= ~(VM_MAYWRITE | VM_MAYEXEC);
     566                 :          0 :         vma->vm_flags |= VM_MIXEDMAP;
     567                 :          0 :         vma->vm_ops = &vmcore_mmap_ops;
     568                 :            : 
     569                 :          0 :         len = 0;
     570                 :            : 
     571         [ #  # ]:          0 :         if (start < elfcorebuf_sz) {
     572                 :          0 :                 u64 pfn;
     573                 :            : 
     574                 :          0 :                 tsz = min(elfcorebuf_sz - (size_t)start, size);
     575         [ #  # ]:          0 :                 pfn = __pa(elfcorebuf + start) >> PAGE_SHIFT;
     576         [ #  # ]:          0 :                 if (remap_pfn_range(vma, vma->vm_start, pfn, tsz,
     577                 :            :                                     vma->vm_page_prot))
     578                 :            :                         return -EAGAIN;
     579                 :          0 :                 size -= tsz;
     580                 :          0 :                 start += tsz;
     581                 :          0 :                 len += tsz;
     582                 :            : 
     583         [ #  # ]:          0 :                 if (size == 0)
     584                 :            :                         return 0;
     585                 :            :         }
     586                 :            : 
     587         [ #  # ]:          0 :         if (start < elfcorebuf_sz + elfnotes_sz) {
     588                 :          0 :                 void *kaddr;
     589                 :            : 
     590                 :            :                 /* We add device dumps before other elf notes because the
     591                 :            :                  * other elf notes may not fill the elf notes buffer
     592                 :            :                  * completely and we will end up with zero-filled data
     593                 :            :                  * between the elf notes and the device dumps. Tools will
     594                 :            :                  * then try to decode this zero-filled data as valid notes
     595                 :            :                  * and we don't want that. Hence, adding device dumps before
     596                 :            :                  * the other elf notes ensure that zero-filled data can be
     597                 :            :                  * avoided. This also ensures that the device dumps and
     598                 :            :                  * other elf notes can be properly mmaped at page aligned
     599                 :            :                  * address.
     600                 :            :                  */
     601                 :            : #ifdef CONFIG_PROC_VMCORE_DEVICE_DUMP
     602                 :            :                 /* Read device dumps */
     603                 :            :                 if (start < elfcorebuf_sz + vmcoredd_orig_sz) {
     604                 :            :                         u64 start_off;
     605                 :            : 
     606                 :            :                         tsz = min(elfcorebuf_sz + vmcoredd_orig_sz -
     607                 :            :                                   (size_t)start, size);
     608                 :            :                         start_off = start - elfcorebuf_sz;
     609                 :            :                         if (vmcoredd_mmap_dumps(vma, vma->vm_start + len,
     610                 :            :                                                 start_off, tsz))
     611                 :            :                                 goto fail;
     612                 :            : 
     613                 :            :                         size -= tsz;
     614                 :            :                         start += tsz;
     615                 :            :                         len += tsz;
     616                 :            : 
     617                 :            :                         /* leave now if filled buffer already */
     618                 :            :                         if (!size)
     619                 :            :                                 return 0;
     620                 :            :                 }
     621                 :            : #endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
     622                 :            : 
     623                 :            :                 /* Read remaining elf notes */
     624                 :          0 :                 tsz = min(elfcorebuf_sz + elfnotes_sz - (size_t)start, size);
     625                 :          0 :                 kaddr = elfnotes_buf + start - elfcorebuf_sz - vmcoredd_orig_sz;
     626         [ #  # ]:          0 :                 if (remap_vmalloc_range_partial(vma, vma->vm_start + len,
     627                 :            :                                                 kaddr, tsz))
     628                 :          0 :                         goto fail;
     629                 :            : 
     630                 :          0 :                 size -= tsz;
     631                 :          0 :                 start += tsz;
     632                 :          0 :                 len += tsz;
     633                 :            : 
     634         [ #  # ]:          0 :                 if (size == 0)
     635                 :            :                         return 0;
     636                 :            :         }
     637                 :            : 
     638         [ #  # ]:          0 :         list_for_each_entry(m, &vmcore_list, list) {
     639         [ #  # ]:          0 :                 if (start < m->offset + m->size) {
     640                 :          0 :                         u64 paddr = 0;
     641                 :            : 
     642                 :          0 :                         tsz = (size_t)min_t(unsigned long long,
     643                 :            :                                             m->offset + m->size - start, size);
     644                 :          0 :                         paddr = m->paddr + start - m->offset;
     645         [ #  # ]:          0 :                         if (vmcore_remap_oldmem_pfn(vma, vma->vm_start + len,
     646                 :          0 :                                                     paddr >> PAGE_SHIFT, tsz,
     647                 :            :                                                     vma->vm_page_prot))
     648                 :          0 :                                 goto fail;
     649                 :          0 :                         size -= tsz;
     650                 :          0 :                         start += tsz;
     651                 :          0 :                         len += tsz;
     652                 :            : 
     653         [ #  # ]:          0 :                         if (size == 0)
     654                 :            :                                 return 0;
     655                 :            :                 }
     656                 :            :         }
     657                 :            : 
     658                 :            :         return 0;
     659                 :          0 : fail:
     660                 :          0 :         do_munmap(vma->vm_mm, vma->vm_start, len, NULL);
     661                 :          0 :         return -EAGAIN;
     662                 :            : }
     663                 :            : #else
     664                 :            : static int mmap_vmcore(struct file *file, struct vm_area_struct *vma)
     665                 :            : {
     666                 :            :         return -ENOSYS;
     667                 :            : }
     668                 :            : #endif
     669                 :            : 
     670                 :            : static const struct proc_ops vmcore_proc_ops = {
     671                 :            :         .proc_read      = read_vmcore,
     672                 :            :         .proc_lseek     = default_llseek,
     673                 :            :         .proc_mmap      = mmap_vmcore,
     674                 :            : };
     675                 :            : 
     676                 :          0 : static struct vmcore* __init get_new_element(void)
     677                 :            : {
     678                 :          0 :         return kzalloc(sizeof(struct vmcore), GFP_KERNEL);
     679                 :            : }
     680                 :            : 
     681                 :          0 : static u64 get_vmcore_size(size_t elfsz, size_t elfnotesegsz,
     682                 :            :                            struct list_head *vc_list)
     683                 :            : {
     684                 :          0 :         u64 size;
     685                 :          0 :         struct vmcore *m;
     686                 :            : 
     687                 :          0 :         size = elfsz + elfnotesegsz;
     688         [ #  # ]:          0 :         list_for_each_entry(m, vc_list, list) {
     689                 :          0 :                 size += m->size;
     690                 :            :         }
     691                 :          0 :         return size;
     692                 :            : }
     693                 :            : 
     694                 :            : /**
     695                 :            :  * update_note_header_size_elf64 - update p_memsz member of each PT_NOTE entry
     696                 :            :  *
     697                 :            :  * @ehdr_ptr: ELF header
     698                 :            :  *
     699                 :            :  * This function updates p_memsz member of each PT_NOTE entry in the
     700                 :            :  * program header table pointed to by @ehdr_ptr to real size of ELF
     701                 :            :  * note segment.
     702                 :            :  */
     703                 :          0 : static int __init update_note_header_size_elf64(const Elf64_Ehdr *ehdr_ptr)
     704                 :            : {
     705                 :          0 :         int i, rc=0;
     706                 :          0 :         Elf64_Phdr *phdr_ptr;
     707                 :          0 :         Elf64_Nhdr *nhdr_ptr;
     708                 :            : 
     709                 :          0 :         phdr_ptr = (Elf64_Phdr *)(ehdr_ptr + 1);
     710         [ #  # ]:          0 :         for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
     711                 :          0 :                 void *notes_section;
     712                 :          0 :                 u64 offset, max_sz, sz, real_sz = 0;
     713         [ #  # ]:          0 :                 if (phdr_ptr->p_type != PT_NOTE)
     714                 :          0 :                         continue;
     715                 :          0 :                 max_sz = phdr_ptr->p_memsz;
     716                 :          0 :                 offset = phdr_ptr->p_offset;
     717         [ #  # ]:          0 :                 notes_section = kmalloc(max_sz, GFP_KERNEL);
     718         [ #  # ]:          0 :                 if (!notes_section)
     719                 :          0 :                         return -ENOMEM;
     720                 :          0 :                 rc = elfcorehdr_read_notes(notes_section, max_sz, &offset);
     721         [ #  # ]:          0 :                 if (rc < 0) {
     722                 :          0 :                         kfree(notes_section);
     723                 :          0 :                         return rc;
     724                 :            :                 }
     725                 :            :                 nhdr_ptr = notes_section;
     726         [ #  # ]:          0 :                 while (nhdr_ptr->n_namesz != 0) {
     727                 :          0 :                         sz = sizeof(Elf64_Nhdr) +
     728                 :          0 :                                 (((u64)nhdr_ptr->n_namesz + 3) & ~3) +
     729                 :          0 :                                 (((u64)nhdr_ptr->n_descsz + 3) & ~3);
     730         [ #  # ]:          0 :                         if ((real_sz + sz) > max_sz) {
     731                 :          0 :                                 pr_warn("Warning: Exceeded p_memsz, dropping PT_NOTE entry n_namesz=0x%x, n_descsz=0x%x\n",
     732                 :            :                                         nhdr_ptr->n_namesz, nhdr_ptr->n_descsz);
     733                 :          0 :                                 break;
     734                 :            :                         }
     735                 :          0 :                         real_sz += sz;
     736                 :          0 :                         nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz);
     737                 :            :                 }
     738                 :          0 :                 kfree(notes_section);
     739                 :          0 :                 phdr_ptr->p_memsz = real_sz;
     740         [ #  # ]:          0 :                 if (real_sz == 0) {
     741                 :          0 :                         pr_warn("Warning: Zero PT_NOTE entries found\n");
     742                 :            :                 }
     743                 :            :         }
     744                 :            : 
     745                 :            :         return 0;
     746                 :            : }
     747                 :            : 
     748                 :            : /**
     749                 :            :  * get_note_number_and_size_elf64 - get the number of PT_NOTE program
     750                 :            :  * headers and sum of real size of their ELF note segment headers and
     751                 :            :  * data.
     752                 :            :  *
     753                 :            :  * @ehdr_ptr: ELF header
     754                 :            :  * @nr_ptnote: buffer for the number of PT_NOTE program headers
     755                 :            :  * @sz_ptnote: buffer for size of unique PT_NOTE program header
     756                 :            :  *
     757                 :            :  * This function is used to merge multiple PT_NOTE program headers
     758                 :            :  * into a unique single one. The resulting unique entry will have
     759                 :            :  * @sz_ptnote in its phdr->p_mem.
     760                 :            :  *
     761                 :            :  * It is assumed that program headers with PT_NOTE type pointed to by
     762                 :            :  * @ehdr_ptr has already been updated by update_note_header_size_elf64
     763                 :            :  * and each of PT_NOTE program headers has actual ELF note segment
     764                 :            :  * size in its p_memsz member.
     765                 :            :  */
     766                 :          0 : static int __init get_note_number_and_size_elf64(const Elf64_Ehdr *ehdr_ptr,
     767                 :            :                                                  int *nr_ptnote, u64 *sz_ptnote)
     768                 :            : {
     769                 :          0 :         int i;
     770                 :          0 :         Elf64_Phdr *phdr_ptr;
     771                 :            : 
     772                 :          0 :         *nr_ptnote = *sz_ptnote = 0;
     773                 :            : 
     774                 :          0 :         phdr_ptr = (Elf64_Phdr *)(ehdr_ptr + 1);
     775         [ #  # ]:          0 :         for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
     776         [ #  # ]:          0 :                 if (phdr_ptr->p_type != PT_NOTE)
     777                 :          0 :                         continue;
     778                 :          0 :                 *nr_ptnote += 1;
     779                 :          0 :                 *sz_ptnote += phdr_ptr->p_memsz;
     780                 :            :         }
     781                 :            : 
     782                 :          0 :         return 0;
     783                 :            : }
     784                 :            : 
     785                 :            : /**
     786                 :            :  * copy_notes_elf64 - copy ELF note segments in a given buffer
     787                 :            :  *
     788                 :            :  * @ehdr_ptr: ELF header
     789                 :            :  * @notes_buf: buffer into which ELF note segments are copied
     790                 :            :  *
     791                 :            :  * This function is used to copy ELF note segment in the 1st kernel
     792                 :            :  * into the buffer @notes_buf in the 2nd kernel. It is assumed that
     793                 :            :  * size of the buffer @notes_buf is equal to or larger than sum of the
     794                 :            :  * real ELF note segment headers and data.
     795                 :            :  *
     796                 :            :  * It is assumed that program headers with PT_NOTE type pointed to by
     797                 :            :  * @ehdr_ptr has already been updated by update_note_header_size_elf64
     798                 :            :  * and each of PT_NOTE program headers has actual ELF note segment
     799                 :            :  * size in its p_memsz member.
     800                 :            :  */
     801                 :          0 : static int __init copy_notes_elf64(const Elf64_Ehdr *ehdr_ptr, char *notes_buf)
     802                 :            : {
     803                 :          0 :         int i, rc=0;
     804                 :          0 :         Elf64_Phdr *phdr_ptr;
     805                 :            : 
     806                 :          0 :         phdr_ptr = (Elf64_Phdr*)(ehdr_ptr + 1);
     807                 :            : 
     808         [ #  # ]:          0 :         for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
     809                 :          0 :                 u64 offset;
     810         [ #  # ]:          0 :                 if (phdr_ptr->p_type != PT_NOTE)
     811                 :          0 :                         continue;
     812                 :          0 :                 offset = phdr_ptr->p_offset;
     813                 :          0 :                 rc = elfcorehdr_read_notes(notes_buf, phdr_ptr->p_memsz,
     814                 :            :                                            &offset);
     815         [ #  # ]:          0 :                 if (rc < 0)
     816                 :          0 :                         return rc;
     817                 :          0 :                 notes_buf += phdr_ptr->p_memsz;
     818                 :            :         }
     819                 :            : 
     820                 :            :         return 0;
     821                 :            : }
     822                 :            : 
     823                 :            : /* Merges all the PT_NOTE headers into one. */
     824                 :          0 : static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
     825                 :            :                                            char **notes_buf, size_t *notes_sz)
     826                 :            : {
     827                 :          0 :         int i, nr_ptnote=0, rc=0;
     828                 :          0 :         char *tmp;
     829                 :          0 :         Elf64_Ehdr *ehdr_ptr;
     830                 :          0 :         Elf64_Phdr phdr;
     831                 :          0 :         u64 phdr_sz = 0, note_off;
     832                 :            : 
     833                 :          0 :         ehdr_ptr = (Elf64_Ehdr *)elfptr;
     834                 :            : 
     835                 :          0 :         rc = update_note_header_size_elf64(ehdr_ptr);
     836         [ #  # ]:          0 :         if (rc < 0)
     837                 :            :                 return rc;
     838                 :            : 
     839                 :          0 :         rc = get_note_number_and_size_elf64(ehdr_ptr, &nr_ptnote, &phdr_sz);
     840         [ #  # ]:          0 :         if (rc < 0)
     841                 :            :                 return rc;
     842                 :            : 
     843                 :          0 :         *notes_sz = roundup(phdr_sz, PAGE_SIZE);
     844                 :          0 :         *notes_buf = vmcore_alloc_buf(*notes_sz);
     845         [ #  # ]:          0 :         if (!*notes_buf)
     846                 :            :                 return -ENOMEM;
     847                 :            : 
     848                 :          0 :         rc = copy_notes_elf64(ehdr_ptr, *notes_buf);
     849         [ #  # ]:          0 :         if (rc < 0)
     850                 :            :                 return rc;
     851                 :            : 
     852                 :            :         /* Prepare merged PT_NOTE program header. */
     853                 :          0 :         phdr.p_type    = PT_NOTE;
     854                 :          0 :         phdr.p_flags   = 0;
     855                 :          0 :         note_off = sizeof(Elf64_Ehdr) +
     856                 :          0 :                         (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf64_Phdr);
     857                 :          0 :         phdr.p_offset  = roundup(note_off, PAGE_SIZE);
     858                 :          0 :         phdr.p_vaddr   = phdr.p_paddr = 0;
     859                 :          0 :         phdr.p_filesz  = phdr.p_memsz = phdr_sz;
     860                 :          0 :         phdr.p_align   = 0;
     861                 :            : 
     862                 :            :         /* Add merged PT_NOTE program header*/
     863                 :          0 :         tmp = elfptr + sizeof(Elf64_Ehdr);
     864                 :          0 :         memcpy(tmp, &phdr, sizeof(phdr));
     865                 :          0 :         tmp += sizeof(phdr);
     866                 :            : 
     867                 :            :         /* Remove unwanted PT_NOTE program headers. */
     868                 :          0 :         i = (nr_ptnote - 1) * sizeof(Elf64_Phdr);
     869                 :          0 :         *elfsz = *elfsz - i;
     870                 :          0 :         memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf64_Ehdr)-sizeof(Elf64_Phdr)));
     871                 :          0 :         memset(elfptr + *elfsz, 0, i);
     872                 :          0 :         *elfsz = roundup(*elfsz, PAGE_SIZE);
     873                 :            : 
     874                 :            :         /* Modify e_phnum to reflect merged headers. */
     875                 :          0 :         ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1;
     876                 :            : 
     877                 :            :         /* Store the size of all notes.  We need this to update the note
     878                 :            :          * header when the device dumps will be added.
     879                 :            :          */
     880                 :          0 :         elfnotes_orig_sz = phdr.p_memsz;
     881                 :            : 
     882                 :          0 :         return 0;
     883                 :            : }
     884                 :            : 
     885                 :            : /**
     886                 :            :  * update_note_header_size_elf32 - update p_memsz member of each PT_NOTE entry
     887                 :            :  *
     888                 :            :  * @ehdr_ptr: ELF header
     889                 :            :  *
     890                 :            :  * This function updates p_memsz member of each PT_NOTE entry in the
     891                 :            :  * program header table pointed to by @ehdr_ptr to real size of ELF
     892                 :            :  * note segment.
     893                 :            :  */
     894                 :          0 : static int __init update_note_header_size_elf32(const Elf32_Ehdr *ehdr_ptr)
     895                 :            : {
     896                 :          0 :         int i, rc=0;
     897                 :          0 :         Elf32_Phdr *phdr_ptr;
     898                 :          0 :         Elf32_Nhdr *nhdr_ptr;
     899                 :            : 
     900                 :          0 :         phdr_ptr = (Elf32_Phdr *)(ehdr_ptr + 1);
     901         [ #  # ]:          0 :         for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
     902                 :          0 :                 void *notes_section;
     903                 :          0 :                 u64 offset, max_sz, sz, real_sz = 0;
     904         [ #  # ]:          0 :                 if (phdr_ptr->p_type != PT_NOTE)
     905                 :          0 :                         continue;
     906                 :          0 :                 max_sz = phdr_ptr->p_memsz;
     907                 :          0 :                 offset = phdr_ptr->p_offset;
     908         [ #  # ]:          0 :                 notes_section = kmalloc(max_sz, GFP_KERNEL);
     909         [ #  # ]:          0 :                 if (!notes_section)
     910                 :          0 :                         return -ENOMEM;
     911                 :          0 :                 rc = elfcorehdr_read_notes(notes_section, max_sz, &offset);
     912         [ #  # ]:          0 :                 if (rc < 0) {
     913                 :          0 :                         kfree(notes_section);
     914                 :          0 :                         return rc;
     915                 :            :                 }
     916                 :            :                 nhdr_ptr = notes_section;
     917         [ #  # ]:          0 :                 while (nhdr_ptr->n_namesz != 0) {
     918                 :          0 :                         sz = sizeof(Elf32_Nhdr) +
     919                 :          0 :                                 (((u64)nhdr_ptr->n_namesz + 3) & ~3) +
     920                 :          0 :                                 (((u64)nhdr_ptr->n_descsz + 3) & ~3);
     921         [ #  # ]:          0 :                         if ((real_sz + sz) > max_sz) {
     922                 :          0 :                                 pr_warn("Warning: Exceeded p_memsz, dropping PT_NOTE entry n_namesz=0x%x, n_descsz=0x%x\n",
     923                 :            :                                         nhdr_ptr->n_namesz, nhdr_ptr->n_descsz);
     924                 :          0 :                                 break;
     925                 :            :                         }
     926                 :          0 :                         real_sz += sz;
     927                 :          0 :                         nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz);
     928                 :            :                 }
     929                 :          0 :                 kfree(notes_section);
     930                 :          0 :                 phdr_ptr->p_memsz = real_sz;
     931         [ #  # ]:          0 :                 if (real_sz == 0) {
     932                 :          0 :                         pr_warn("Warning: Zero PT_NOTE entries found\n");
     933                 :            :                 }
     934                 :            :         }
     935                 :            : 
     936                 :            :         return 0;
     937                 :            : }
     938                 :            : 
     939                 :            : /**
     940                 :            :  * get_note_number_and_size_elf32 - get the number of PT_NOTE program
     941                 :            :  * headers and sum of real size of their ELF note segment headers and
     942                 :            :  * data.
     943                 :            :  *
     944                 :            :  * @ehdr_ptr: ELF header
     945                 :            :  * @nr_ptnote: buffer for the number of PT_NOTE program headers
     946                 :            :  * @sz_ptnote: buffer for size of unique PT_NOTE program header
     947                 :            :  *
     948                 :            :  * This function is used to merge multiple PT_NOTE program headers
     949                 :            :  * into a unique single one. The resulting unique entry will have
     950                 :            :  * @sz_ptnote in its phdr->p_mem.
     951                 :            :  *
     952                 :            :  * It is assumed that program headers with PT_NOTE type pointed to by
     953                 :            :  * @ehdr_ptr has already been updated by update_note_header_size_elf32
     954                 :            :  * and each of PT_NOTE program headers has actual ELF note segment
     955                 :            :  * size in its p_memsz member.
     956                 :            :  */
     957                 :          0 : static int __init get_note_number_and_size_elf32(const Elf32_Ehdr *ehdr_ptr,
     958                 :            :                                                  int *nr_ptnote, u64 *sz_ptnote)
     959                 :            : {
     960                 :          0 :         int i;
     961                 :          0 :         Elf32_Phdr *phdr_ptr;
     962                 :            : 
     963                 :          0 :         *nr_ptnote = *sz_ptnote = 0;
     964                 :            : 
     965                 :          0 :         phdr_ptr = (Elf32_Phdr *)(ehdr_ptr + 1);
     966         [ #  # ]:          0 :         for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
     967         [ #  # ]:          0 :                 if (phdr_ptr->p_type != PT_NOTE)
     968                 :          0 :                         continue;
     969                 :          0 :                 *nr_ptnote += 1;
     970                 :          0 :                 *sz_ptnote += phdr_ptr->p_memsz;
     971                 :            :         }
     972                 :            : 
     973                 :          0 :         return 0;
     974                 :            : }
     975                 :            : 
     976                 :            : /**
     977                 :            :  * copy_notes_elf32 - copy ELF note segments in a given buffer
     978                 :            :  *
     979                 :            :  * @ehdr_ptr: ELF header
     980                 :            :  * @notes_buf: buffer into which ELF note segments are copied
     981                 :            :  *
     982                 :            :  * This function is used to copy ELF note segment in the 1st kernel
     983                 :            :  * into the buffer @notes_buf in the 2nd kernel. It is assumed that
     984                 :            :  * size of the buffer @notes_buf is equal to or larger than sum of the
     985                 :            :  * real ELF note segment headers and data.
     986                 :            :  *
     987                 :            :  * It is assumed that program headers with PT_NOTE type pointed to by
     988                 :            :  * @ehdr_ptr has already been updated by update_note_header_size_elf32
     989                 :            :  * and each of PT_NOTE program headers has actual ELF note segment
     990                 :            :  * size in its p_memsz member.
     991                 :            :  */
     992                 :          0 : static int __init copy_notes_elf32(const Elf32_Ehdr *ehdr_ptr, char *notes_buf)
     993                 :            : {
     994                 :          0 :         int i, rc=0;
     995                 :          0 :         Elf32_Phdr *phdr_ptr;
     996                 :            : 
     997                 :          0 :         phdr_ptr = (Elf32_Phdr*)(ehdr_ptr + 1);
     998                 :            : 
     999         [ #  # ]:          0 :         for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
    1000                 :          0 :                 u64 offset;
    1001         [ #  # ]:          0 :                 if (phdr_ptr->p_type != PT_NOTE)
    1002                 :          0 :                         continue;
    1003                 :          0 :                 offset = phdr_ptr->p_offset;
    1004                 :          0 :                 rc = elfcorehdr_read_notes(notes_buf, phdr_ptr->p_memsz,
    1005                 :            :                                            &offset);
    1006         [ #  # ]:          0 :                 if (rc < 0)
    1007                 :          0 :                         return rc;
    1008                 :          0 :                 notes_buf += phdr_ptr->p_memsz;
    1009                 :            :         }
    1010                 :            : 
    1011                 :            :         return 0;
    1012                 :            : }
    1013                 :            : 
    1014                 :            : /* Merges all the PT_NOTE headers into one. */
    1015                 :          0 : static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
    1016                 :            :                                            char **notes_buf, size_t *notes_sz)
    1017                 :            : {
    1018                 :          0 :         int i, nr_ptnote=0, rc=0;
    1019                 :          0 :         char *tmp;
    1020                 :          0 :         Elf32_Ehdr *ehdr_ptr;
    1021                 :          0 :         Elf32_Phdr phdr;
    1022                 :          0 :         u64 phdr_sz = 0, note_off;
    1023                 :            : 
    1024                 :          0 :         ehdr_ptr = (Elf32_Ehdr *)elfptr;
    1025                 :            : 
    1026                 :          0 :         rc = update_note_header_size_elf32(ehdr_ptr);
    1027         [ #  # ]:          0 :         if (rc < 0)
    1028                 :            :                 return rc;
    1029                 :            : 
    1030                 :          0 :         rc = get_note_number_and_size_elf32(ehdr_ptr, &nr_ptnote, &phdr_sz);
    1031         [ #  # ]:          0 :         if (rc < 0)
    1032                 :            :                 return rc;
    1033                 :            : 
    1034                 :          0 :         *notes_sz = roundup(phdr_sz, PAGE_SIZE);
    1035                 :          0 :         *notes_buf = vmcore_alloc_buf(*notes_sz);
    1036         [ #  # ]:          0 :         if (!*notes_buf)
    1037                 :            :                 return -ENOMEM;
    1038                 :            : 
    1039                 :          0 :         rc = copy_notes_elf32(ehdr_ptr, *notes_buf);
    1040         [ #  # ]:          0 :         if (rc < 0)
    1041                 :            :                 return rc;
    1042                 :            : 
    1043                 :            :         /* Prepare merged PT_NOTE program header. */
    1044                 :          0 :         phdr.p_type    = PT_NOTE;
    1045                 :          0 :         phdr.p_flags   = 0;
    1046                 :          0 :         note_off = sizeof(Elf32_Ehdr) +
    1047                 :          0 :                         (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf32_Phdr);
    1048                 :          0 :         phdr.p_offset  = roundup(note_off, PAGE_SIZE);
    1049                 :          0 :         phdr.p_vaddr   = phdr.p_paddr = 0;
    1050                 :          0 :         phdr.p_filesz  = phdr.p_memsz = phdr_sz;
    1051                 :          0 :         phdr.p_align   = 0;
    1052                 :            : 
    1053                 :            :         /* Add merged PT_NOTE program header*/
    1054                 :          0 :         tmp = elfptr + sizeof(Elf32_Ehdr);
    1055                 :          0 :         memcpy(tmp, &phdr, sizeof(phdr));
    1056                 :          0 :         tmp += sizeof(phdr);
    1057                 :            : 
    1058                 :            :         /* Remove unwanted PT_NOTE program headers. */
    1059                 :          0 :         i = (nr_ptnote - 1) * sizeof(Elf32_Phdr);
    1060                 :          0 :         *elfsz = *elfsz - i;
    1061                 :          0 :         memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf32_Ehdr)-sizeof(Elf32_Phdr)));
    1062                 :          0 :         memset(elfptr + *elfsz, 0, i);
    1063                 :          0 :         *elfsz = roundup(*elfsz, PAGE_SIZE);
    1064                 :            : 
    1065                 :            :         /* Modify e_phnum to reflect merged headers. */
    1066                 :          0 :         ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1;
    1067                 :            : 
    1068                 :            :         /* Store the size of all notes.  We need this to update the note
    1069                 :            :          * header when the device dumps will be added.
    1070                 :            :          */
    1071                 :          0 :         elfnotes_orig_sz = phdr.p_memsz;
    1072                 :            : 
    1073                 :          0 :         return 0;
    1074                 :            : }
    1075                 :            : 
    1076                 :            : /* Add memory chunks represented by program headers to vmcore list. Also update
    1077                 :            :  * the new offset fields of exported program headers. */
    1078                 :          0 : static int __init process_ptload_program_headers_elf64(char *elfptr,
    1079                 :            :                                                 size_t elfsz,
    1080                 :            :                                                 size_t elfnotes_sz,
    1081                 :            :                                                 struct list_head *vc_list)
    1082                 :            : {
    1083                 :          0 :         int i;
    1084                 :          0 :         Elf64_Ehdr *ehdr_ptr;
    1085                 :          0 :         Elf64_Phdr *phdr_ptr;
    1086                 :          0 :         loff_t vmcore_off;
    1087                 :          0 :         struct vmcore *new;
    1088                 :            : 
    1089                 :          0 :         ehdr_ptr = (Elf64_Ehdr *)elfptr;
    1090                 :          0 :         phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); /* PT_NOTE hdr */
    1091                 :            : 
    1092                 :            :         /* Skip Elf header, program headers and Elf note segment. */
    1093                 :          0 :         vmcore_off = elfsz + elfnotes_sz;
    1094                 :            : 
    1095         [ #  # ]:          0 :         for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
    1096                 :          0 :                 u64 paddr, start, end, size;
    1097                 :            : 
    1098         [ #  # ]:          0 :                 if (phdr_ptr->p_type != PT_LOAD)
    1099                 :          0 :                         continue;
    1100                 :            : 
    1101                 :          0 :                 paddr = phdr_ptr->p_offset;
    1102                 :          0 :                 start = rounddown(paddr, PAGE_SIZE);
    1103                 :          0 :                 end = roundup(paddr + phdr_ptr->p_memsz, PAGE_SIZE);
    1104                 :          0 :                 size = end - start;
    1105                 :            : 
    1106                 :            :                 /* Add this contiguous chunk of memory to vmcore list.*/
    1107                 :          0 :                 new = get_new_element();
    1108         [ #  # ]:          0 :                 if (!new)
    1109                 :            :                         return -ENOMEM;
    1110                 :          0 :                 new->paddr = start;
    1111                 :          0 :                 new->size = size;
    1112                 :          0 :                 list_add_tail(&new->list, vc_list);
    1113                 :            : 
    1114                 :            :                 /* Update the program header offset. */
    1115                 :          0 :                 phdr_ptr->p_offset = vmcore_off + (paddr - start);
    1116                 :          0 :                 vmcore_off = vmcore_off + size;
    1117                 :            :         }
    1118                 :            :         return 0;
    1119                 :            : }
    1120                 :            : 
    1121                 :          0 : static int __init process_ptload_program_headers_elf32(char *elfptr,
    1122                 :            :                                                 size_t elfsz,
    1123                 :            :                                                 size_t elfnotes_sz,
    1124                 :            :                                                 struct list_head *vc_list)
    1125                 :            : {
    1126                 :          0 :         int i;
    1127                 :          0 :         Elf32_Ehdr *ehdr_ptr;
    1128                 :          0 :         Elf32_Phdr *phdr_ptr;
    1129                 :          0 :         loff_t vmcore_off;
    1130                 :          0 :         struct vmcore *new;
    1131                 :            : 
    1132                 :          0 :         ehdr_ptr = (Elf32_Ehdr *)elfptr;
    1133                 :          0 :         phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); /* PT_NOTE hdr */
    1134                 :            : 
    1135                 :            :         /* Skip Elf header, program headers and Elf note segment. */
    1136                 :          0 :         vmcore_off = elfsz + elfnotes_sz;
    1137                 :            : 
    1138         [ #  # ]:          0 :         for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
    1139                 :          0 :                 u64 paddr, start, end, size;
    1140                 :            : 
    1141         [ #  # ]:          0 :                 if (phdr_ptr->p_type != PT_LOAD)
    1142                 :          0 :                         continue;
    1143                 :            : 
    1144                 :          0 :                 paddr = phdr_ptr->p_offset;
    1145                 :          0 :                 start = rounddown(paddr, PAGE_SIZE);
    1146                 :          0 :                 end = roundup(paddr + phdr_ptr->p_memsz, PAGE_SIZE);
    1147                 :          0 :                 size = end - start;
    1148                 :            : 
    1149                 :            :                 /* Add this contiguous chunk of memory to vmcore list.*/
    1150                 :          0 :                 new = get_new_element();
    1151         [ #  # ]:          0 :                 if (!new)
    1152                 :            :                         return -ENOMEM;
    1153                 :          0 :                 new->paddr = start;
    1154                 :          0 :                 new->size = size;
    1155                 :          0 :                 list_add_tail(&new->list, vc_list);
    1156                 :            : 
    1157                 :            :                 /* Update the program header offset */
    1158                 :          0 :                 phdr_ptr->p_offset = vmcore_off + (paddr - start);
    1159                 :          0 :                 vmcore_off = vmcore_off + size;
    1160                 :            :         }
    1161                 :            :         return 0;
    1162                 :            : }
    1163                 :            : 
    1164                 :            : /* Sets offset fields of vmcore elements. */
    1165                 :          0 : static void set_vmcore_list_offsets(size_t elfsz, size_t elfnotes_sz,
    1166                 :            :                                     struct list_head *vc_list)
    1167                 :            : {
    1168                 :          0 :         loff_t vmcore_off;
    1169                 :          0 :         struct vmcore *m;
    1170                 :            : 
    1171                 :            :         /* Skip Elf header, program headers and Elf note segment. */
    1172                 :          0 :         vmcore_off = elfsz + elfnotes_sz;
    1173                 :            : 
    1174   [ #  #  #  # ]:          0 :         list_for_each_entry(m, vc_list, list) {
    1175                 :          0 :                 m->offset = vmcore_off;
    1176                 :          0 :                 vmcore_off += m->size;
    1177                 :            :         }
    1178                 :            : }
    1179                 :            : 
    1180                 :          0 : static void free_elfcorebuf(void)
    1181                 :            : {
    1182                 :          0 :         free_pages((unsigned long)elfcorebuf, get_order(elfcorebuf_sz_orig));
    1183                 :          0 :         elfcorebuf = NULL;
    1184                 :          0 :         vfree(elfnotes_buf);
    1185                 :          0 :         elfnotes_buf = NULL;
    1186                 :          0 : }
    1187                 :            : 
    1188                 :          0 : static int __init parse_crash_elf64_headers(void)
    1189                 :            : {
    1190                 :          0 :         int rc=0;
    1191                 :          0 :         Elf64_Ehdr ehdr;
    1192                 :          0 :         u64 addr;
    1193                 :            : 
    1194                 :          0 :         addr = elfcorehdr_addr;
    1195                 :            : 
    1196                 :            :         /* Read Elf header */
    1197                 :          0 :         rc = elfcorehdr_read((char *)&ehdr, sizeof(Elf64_Ehdr), &addr);
    1198         [ #  # ]:          0 :         if (rc < 0)
    1199                 :            :                 return rc;
    1200                 :            : 
    1201                 :            :         /* Do some basic Verification. */
    1202         [ #  # ]:          0 :         if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
    1203         [ #  # ]:          0 :                 (ehdr.e_type != ET_CORE) ||
    1204                 :            :                 !vmcore_elf64_check_arch(&ehdr) ||
    1205         [ #  # ]:          0 :                 ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
    1206                 :          0 :                 ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
    1207         [ #  # ]:          0 :                 ehdr.e_version != EV_CURRENT ||
    1208         [ #  # ]:          0 :                 ehdr.e_ehsize != sizeof(Elf64_Ehdr) ||
    1209                 :          0 :                 ehdr.e_phentsize != sizeof(Elf64_Phdr) ||
    1210         [ #  # ]:          0 :                 ehdr.e_phnum == 0) {
    1211                 :          0 :                 pr_warn("Warning: Core image elf header is not sane\n");
    1212                 :          0 :                 return -EINVAL;
    1213                 :            :         }
    1214                 :            : 
    1215                 :            :         /* Read in all elf headers. */
    1216                 :          0 :         elfcorebuf_sz_orig = sizeof(Elf64_Ehdr) +
    1217                 :          0 :                                 ehdr.e_phnum * sizeof(Elf64_Phdr);
    1218                 :          0 :         elfcorebuf_sz = elfcorebuf_sz_orig;
    1219                 :          0 :         elfcorebuf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
    1220                 :          0 :                                               get_order(elfcorebuf_sz_orig));
    1221         [ #  # ]:          0 :         if (!elfcorebuf)
    1222                 :            :                 return -ENOMEM;
    1223                 :          0 :         addr = elfcorehdr_addr;
    1224                 :          0 :         rc = elfcorehdr_read(elfcorebuf, elfcorebuf_sz_orig, &addr);
    1225         [ #  # ]:          0 :         if (rc < 0)
    1226                 :          0 :                 goto fail;
    1227                 :            : 
    1228                 :            :         /* Merge all PT_NOTE headers into one. */
    1229                 :          0 :         rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz,
    1230                 :            :                                       &elfnotes_buf, &elfnotes_sz);
    1231         [ #  # ]:          0 :         if (rc)
    1232                 :          0 :                 goto fail;
    1233                 :          0 :         rc = process_ptload_program_headers_elf64(elfcorebuf, elfcorebuf_sz,
    1234                 :            :                                                   elfnotes_sz, &vmcore_list);
    1235         [ #  # ]:          0 :         if (rc)
    1236                 :          0 :                 goto fail;
    1237                 :          0 :         set_vmcore_list_offsets(elfcorebuf_sz, elfnotes_sz, &vmcore_list);
    1238                 :            :         return 0;
    1239                 :          0 : fail:
    1240                 :          0 :         free_elfcorebuf();
    1241                 :          0 :         return rc;
    1242                 :            : }
    1243                 :            : 
    1244                 :          0 : static int __init parse_crash_elf32_headers(void)
    1245                 :            : {
    1246                 :          0 :         int rc=0;
    1247                 :          0 :         Elf32_Ehdr ehdr;
    1248                 :          0 :         u64 addr;
    1249                 :            : 
    1250                 :          0 :         addr = elfcorehdr_addr;
    1251                 :            : 
    1252                 :            :         /* Read Elf header */
    1253                 :          0 :         rc = elfcorehdr_read((char *)&ehdr, sizeof(Elf32_Ehdr), &addr);
    1254         [ #  # ]:          0 :         if (rc < 0)
    1255                 :            :                 return rc;
    1256                 :            : 
    1257                 :            :         /* Do some basic Verification. */
    1258         [ #  # ]:          0 :         if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
    1259         [ #  # ]:          0 :                 (ehdr.e_type != ET_CORE) ||
    1260                 :            :                 !vmcore_elf32_check_arch(&ehdr) ||
    1261         [ #  # ]:          0 :                 ehdr.e_ident[EI_CLASS] != ELFCLASS32||
    1262                 :          0 :                 ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
    1263         [ #  # ]:          0 :                 ehdr.e_version != EV_CURRENT ||
    1264         [ #  # ]:          0 :                 ehdr.e_ehsize != sizeof(Elf32_Ehdr) ||
    1265                 :          0 :                 ehdr.e_phentsize != sizeof(Elf32_Phdr) ||
    1266         [ #  # ]:          0 :                 ehdr.e_phnum == 0) {
    1267                 :          0 :                 pr_warn("Warning: Core image elf header is not sane\n");
    1268                 :          0 :                 return -EINVAL;
    1269                 :            :         }
    1270                 :            : 
    1271                 :            :         /* Read in all elf headers. */
    1272                 :          0 :         elfcorebuf_sz_orig = sizeof(Elf32_Ehdr) + ehdr.e_phnum * sizeof(Elf32_Phdr);
    1273                 :          0 :         elfcorebuf_sz = elfcorebuf_sz_orig;
    1274                 :          0 :         elfcorebuf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
    1275                 :          0 :                                               get_order(elfcorebuf_sz_orig));
    1276         [ #  # ]:          0 :         if (!elfcorebuf)
    1277                 :            :                 return -ENOMEM;
    1278                 :          0 :         addr = elfcorehdr_addr;
    1279                 :          0 :         rc = elfcorehdr_read(elfcorebuf, elfcorebuf_sz_orig, &addr);
    1280         [ #  # ]:          0 :         if (rc < 0)
    1281                 :          0 :                 goto fail;
    1282                 :            : 
    1283                 :            :         /* Merge all PT_NOTE headers into one. */
    1284                 :          0 :         rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz,
    1285                 :            :                                       &elfnotes_buf, &elfnotes_sz);
    1286         [ #  # ]:          0 :         if (rc)
    1287                 :          0 :                 goto fail;
    1288                 :          0 :         rc = process_ptload_program_headers_elf32(elfcorebuf, elfcorebuf_sz,
    1289                 :            :                                                   elfnotes_sz, &vmcore_list);
    1290         [ #  # ]:          0 :         if (rc)
    1291                 :          0 :                 goto fail;
    1292                 :          0 :         set_vmcore_list_offsets(elfcorebuf_sz, elfnotes_sz, &vmcore_list);
    1293                 :            :         return 0;
    1294                 :          0 : fail:
    1295                 :          0 :         free_elfcorebuf();
    1296                 :          0 :         return rc;
    1297                 :            : }
    1298                 :            : 
    1299                 :          0 : static int __init parse_crash_elf_headers(void)
    1300                 :            : {
    1301                 :          0 :         unsigned char e_ident[EI_NIDENT];
    1302                 :          0 :         u64 addr;
    1303                 :          0 :         int rc=0;
    1304                 :            : 
    1305                 :          0 :         addr = elfcorehdr_addr;
    1306                 :          0 :         rc = elfcorehdr_read(e_ident, EI_NIDENT, &addr);
    1307         [ #  # ]:          0 :         if (rc < 0)
    1308                 :            :                 return rc;
    1309         [ #  # ]:          0 :         if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
    1310                 :          0 :                 pr_warn("Warning: Core image elf header not found\n");
    1311                 :          0 :                 return -EINVAL;
    1312                 :            :         }
    1313                 :            : 
    1314         [ #  # ]:          0 :         if (e_ident[EI_CLASS] == ELFCLASS64) {
    1315                 :          0 :                 rc = parse_crash_elf64_headers();
    1316         [ #  # ]:          0 :                 if (rc)
    1317                 :            :                         return rc;
    1318         [ #  # ]:          0 :         } else if (e_ident[EI_CLASS] == ELFCLASS32) {
    1319                 :          0 :                 rc = parse_crash_elf32_headers();
    1320         [ #  # ]:          0 :                 if (rc)
    1321                 :            :                         return rc;
    1322                 :            :         } else {
    1323                 :          0 :                 pr_warn("Warning: Core image elf header is not sane\n");
    1324                 :          0 :                 return -EINVAL;
    1325                 :            :         }
    1326                 :            : 
    1327                 :            :         /* Determine vmcore size. */
    1328                 :          0 :         vmcore_size = get_vmcore_size(elfcorebuf_sz, elfnotes_sz,
    1329                 :            :                                       &vmcore_list);
    1330                 :            : 
    1331                 :          0 :         return 0;
    1332                 :            : }
    1333                 :            : 
    1334                 :            : #ifdef CONFIG_PROC_VMCORE_DEVICE_DUMP
    1335                 :            : /**
    1336                 :            :  * vmcoredd_write_header - Write vmcore device dump header at the
    1337                 :            :  * beginning of the dump's buffer.
    1338                 :            :  * @buf: Output buffer where the note is written
    1339                 :            :  * @data: Dump info
    1340                 :            :  * @size: Size of the dump
    1341                 :            :  *
    1342                 :            :  * Fills beginning of the dump's buffer with vmcore device dump header.
    1343                 :            :  */
    1344                 :            : static void vmcoredd_write_header(void *buf, struct vmcoredd_data *data,
    1345                 :            :                                   u32 size)
    1346                 :            : {
    1347                 :            :         struct vmcoredd_header *vdd_hdr = (struct vmcoredd_header *)buf;
    1348                 :            : 
    1349                 :            :         vdd_hdr->n_namesz = sizeof(vdd_hdr->name);
    1350                 :            :         vdd_hdr->n_descsz = size + sizeof(vdd_hdr->dump_name);
    1351                 :            :         vdd_hdr->n_type = NT_VMCOREDD;
    1352                 :            : 
    1353                 :            :         strncpy((char *)vdd_hdr->name, VMCOREDD_NOTE_NAME,
    1354                 :            :                 sizeof(vdd_hdr->name));
    1355                 :            :         memcpy(vdd_hdr->dump_name, data->dump_name, sizeof(vdd_hdr->dump_name));
    1356                 :            : }
    1357                 :            : 
    1358                 :            : /**
    1359                 :            :  * vmcoredd_update_program_headers - Update all Elf program headers
    1360                 :            :  * @elfptr: Pointer to elf header
    1361                 :            :  * @elfnotesz: Size of elf notes aligned to page size
    1362                 :            :  * @vmcoreddsz: Size of device dumps to be added to elf note header
    1363                 :            :  *
    1364                 :            :  * Determine type of Elf header (Elf64 or Elf32) and update the elf note size.
    1365                 :            :  * Also update the offsets of all the program headers after the elf note header.
    1366                 :            :  */
    1367                 :            : static void vmcoredd_update_program_headers(char *elfptr, size_t elfnotesz,
    1368                 :            :                                             size_t vmcoreddsz)
    1369                 :            : {
    1370                 :            :         unsigned char *e_ident = (unsigned char *)elfptr;
    1371                 :            :         u64 start, end, size;
    1372                 :            :         loff_t vmcore_off;
    1373                 :            :         u32 i;
    1374                 :            : 
    1375                 :            :         vmcore_off = elfcorebuf_sz + elfnotesz;
    1376                 :            : 
    1377                 :            :         if (e_ident[EI_CLASS] == ELFCLASS64) {
    1378                 :            :                 Elf64_Ehdr *ehdr = (Elf64_Ehdr *)elfptr;
    1379                 :            :                 Elf64_Phdr *phdr = (Elf64_Phdr *)(elfptr + sizeof(Elf64_Ehdr));
    1380                 :            : 
    1381                 :            :                 /* Update all program headers */
    1382                 :            :                 for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
    1383                 :            :                         if (phdr->p_type == PT_NOTE) {
    1384                 :            :                                 /* Update note size */
    1385                 :            :                                 phdr->p_memsz = elfnotes_orig_sz + vmcoreddsz;
    1386                 :            :                                 phdr->p_filesz = phdr->p_memsz;
    1387                 :            :                                 continue;
    1388                 :            :                         }
    1389                 :            : 
    1390                 :            :                         start = rounddown(phdr->p_offset, PAGE_SIZE);
    1391                 :            :                         end = roundup(phdr->p_offset + phdr->p_memsz,
    1392                 :            :                                       PAGE_SIZE);
    1393                 :            :                         size = end - start;
    1394                 :            :                         phdr->p_offset = vmcore_off + (phdr->p_offset - start);
    1395                 :            :                         vmcore_off += size;
    1396                 :            :                 }
    1397                 :            :         } else {
    1398                 :            :                 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elfptr;
    1399                 :            :                 Elf32_Phdr *phdr = (Elf32_Phdr *)(elfptr + sizeof(Elf32_Ehdr));
    1400                 :            : 
    1401                 :            :                 /* Update all program headers */
    1402                 :            :                 for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
    1403                 :            :                         if (phdr->p_type == PT_NOTE) {
    1404                 :            :                                 /* Update note size */
    1405                 :            :                                 phdr->p_memsz = elfnotes_orig_sz + vmcoreddsz;
    1406                 :            :                                 phdr->p_filesz = phdr->p_memsz;
    1407                 :            :                                 continue;
    1408                 :            :                         }
    1409                 :            : 
    1410                 :            :                         start = rounddown(phdr->p_offset, PAGE_SIZE);
    1411                 :            :                         end = roundup(phdr->p_offset + phdr->p_memsz,
    1412                 :            :                                       PAGE_SIZE);
    1413                 :            :                         size = end - start;
    1414                 :            :                         phdr->p_offset = vmcore_off + (phdr->p_offset - start);
    1415                 :            :                         vmcore_off += size;
    1416                 :            :                 }
    1417                 :            :         }
    1418                 :            : }
    1419                 :            : 
    1420                 :            : /**
    1421                 :            :  * vmcoredd_update_size - Update the total size of the device dumps and update
    1422                 :            :  * Elf header
    1423                 :            :  * @dump_size: Size of the current device dump to be added to total size
    1424                 :            :  *
    1425                 :            :  * Update the total size of all the device dumps and update the Elf program
    1426                 :            :  * headers. Calculate the new offsets for the vmcore list and update the
    1427                 :            :  * total vmcore size.
    1428                 :            :  */
    1429                 :            : static void vmcoredd_update_size(size_t dump_size)
    1430                 :            : {
    1431                 :            :         vmcoredd_orig_sz += dump_size;
    1432                 :            :         elfnotes_sz = roundup(elfnotes_orig_sz, PAGE_SIZE) + vmcoredd_orig_sz;
    1433                 :            :         vmcoredd_update_program_headers(elfcorebuf, elfnotes_sz,
    1434                 :            :                                         vmcoredd_orig_sz);
    1435                 :            : 
    1436                 :            :         /* Update vmcore list offsets */
    1437                 :            :         set_vmcore_list_offsets(elfcorebuf_sz, elfnotes_sz, &vmcore_list);
    1438                 :            : 
    1439                 :            :         vmcore_size = get_vmcore_size(elfcorebuf_sz, elfnotes_sz,
    1440                 :            :                                       &vmcore_list);
    1441                 :            :         proc_vmcore->size = vmcore_size;
    1442                 :            : }
    1443                 :            : 
    1444                 :            : /**
    1445                 :            :  * vmcore_add_device_dump - Add a buffer containing device dump to vmcore
    1446                 :            :  * @data: dump info.
    1447                 :            :  *
    1448                 :            :  * Allocate a buffer and invoke the calling driver's dump collect routine.
    1449                 :            :  * Write Elf note at the beginning of the buffer to indicate vmcore device
    1450                 :            :  * dump and add the dump to global list.
    1451                 :            :  */
    1452                 :            : int vmcore_add_device_dump(struct vmcoredd_data *data)
    1453                 :            : {
    1454                 :            :         struct vmcoredd_node *dump;
    1455                 :            :         void *buf = NULL;
    1456                 :            :         size_t data_size;
    1457                 :            :         int ret;
    1458                 :            : 
    1459                 :            :         if (vmcoredd_disabled) {
    1460                 :            :                 pr_err_once("Device dump is disabled\n");
    1461                 :            :                 return -EINVAL;
    1462                 :            :         }
    1463                 :            : 
    1464                 :            :         if (!data || !strlen(data->dump_name) ||
    1465                 :            :             !data->vmcoredd_callback || !data->size)
    1466                 :            :                 return -EINVAL;
    1467                 :            : 
    1468                 :            :         dump = vzalloc(sizeof(*dump));
    1469                 :            :         if (!dump) {
    1470                 :            :                 ret = -ENOMEM;
    1471                 :            :                 goto out_err;
    1472                 :            :         }
    1473                 :            : 
    1474                 :            :         /* Keep size of the buffer page aligned so that it can be mmaped */
    1475                 :            :         data_size = roundup(sizeof(struct vmcoredd_header) + data->size,
    1476                 :            :                             PAGE_SIZE);
    1477                 :            : 
    1478                 :            :         /* Allocate buffer for driver's to write their dumps */
    1479                 :            :         buf = vmcore_alloc_buf(data_size);
    1480                 :            :         if (!buf) {
    1481                 :            :                 ret = -ENOMEM;
    1482                 :            :                 goto out_err;
    1483                 :            :         }
    1484                 :            : 
    1485                 :            :         vmcoredd_write_header(buf, data, data_size -
    1486                 :            :                               sizeof(struct vmcoredd_header));
    1487                 :            : 
    1488                 :            :         /* Invoke the driver's dump collection routing */
    1489                 :            :         ret = data->vmcoredd_callback(data, buf +
    1490                 :            :                                       sizeof(struct vmcoredd_header));
    1491                 :            :         if (ret)
    1492                 :            :                 goto out_err;
    1493                 :            : 
    1494                 :            :         dump->buf = buf;
    1495                 :            :         dump->size = data_size;
    1496                 :            : 
    1497                 :            :         /* Add the dump to driver sysfs list */
    1498                 :            :         mutex_lock(&vmcoredd_mutex);
    1499                 :            :         list_add_tail(&dump->list, &vmcoredd_list);
    1500                 :            :         mutex_unlock(&vmcoredd_mutex);
    1501                 :            : 
    1502                 :            :         vmcoredd_update_size(data_size);
    1503                 :            :         return 0;
    1504                 :            : 
    1505                 :            : out_err:
    1506                 :            :         if (buf)
    1507                 :            :                 vfree(buf);
    1508                 :            : 
    1509                 :            :         if (dump)
    1510                 :            :                 vfree(dump);
    1511                 :            : 
    1512                 :            :         return ret;
    1513                 :            : }
    1514                 :            : EXPORT_SYMBOL(vmcore_add_device_dump);
    1515                 :            : #endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
    1516                 :            : 
    1517                 :            : /* Free all dumps in vmcore device dump list */
    1518                 :          0 : static void vmcore_free_device_dumps(void)
    1519                 :            : {
    1520                 :            : #ifdef CONFIG_PROC_VMCORE_DEVICE_DUMP
    1521                 :            :         mutex_lock(&vmcoredd_mutex);
    1522                 :            :         while (!list_empty(&vmcoredd_list)) {
    1523                 :            :                 struct vmcoredd_node *dump;
    1524                 :            : 
    1525                 :            :                 dump = list_first_entry(&vmcoredd_list, struct vmcoredd_node,
    1526                 :            :                                         list);
    1527                 :            :                 list_del(&dump->list);
    1528                 :            :                 vfree(dump->buf);
    1529                 :            :                 vfree(dump);
    1530                 :            :         }
    1531                 :            :         mutex_unlock(&vmcoredd_mutex);
    1532                 :            : #endif /* CONFIG_PROC_VMCORE_DEVICE_DUMP */
    1533                 :          0 : }
    1534                 :            : 
    1535                 :            : /* Init function for vmcore module. */
    1536                 :         30 : static int __init vmcore_init(void)
    1537                 :            : {
    1538                 :         30 :         int rc = 0;
    1539                 :            : 
    1540                 :            :         /* Allow architectures to allocate ELF header in 2nd kernel */
    1541                 :         30 :         rc = elfcorehdr_alloc(&elfcorehdr_addr, &elfcorehdr_size);
    1542         [ +  - ]:         30 :         if (rc)
    1543                 :            :                 return rc;
    1544                 :            :         /*
    1545                 :            :          * If elfcorehdr= has been passed in cmdline or created in 2nd kernel,
    1546                 :            :          * then capture the dump.
    1547                 :            :          */
    1548         [ -  + ]:         30 :         if (!(is_vmcore_usable()))
    1549                 :            :                 return rc;
    1550                 :          0 :         rc = parse_crash_elf_headers();
    1551         [ #  # ]:          0 :         if (rc) {
    1552                 :          0 :                 pr_warn("Kdump: vmcore not initialized\n");
    1553                 :          0 :                 return rc;
    1554                 :            :         }
    1555                 :          0 :         elfcorehdr_free(elfcorehdr_addr);
    1556                 :          0 :         elfcorehdr_addr = ELFCORE_ADDR_ERR;
    1557                 :            : 
    1558                 :          0 :         proc_vmcore = proc_create("vmcore", S_IRUSR, NULL, &vmcore_proc_ops);
    1559         [ #  # ]:          0 :         if (proc_vmcore)
    1560                 :          0 :                 proc_vmcore->size = vmcore_size;
    1561                 :            :         return 0;
    1562                 :            : }
    1563                 :            : fs_initcall(vmcore_init);
    1564                 :            : 
    1565                 :            : /* Cleanup function for vmcore module. */
    1566                 :          0 : void vmcore_cleanup(void)
    1567                 :            : {
    1568         [ #  # ]:          0 :         if (proc_vmcore) {
    1569                 :          0 :                 proc_remove(proc_vmcore);
    1570                 :          0 :                 proc_vmcore = NULL;
    1571                 :            :         }
    1572                 :            : 
    1573                 :            :         /* clear the vmcore list. */
    1574         [ #  # ]:          0 :         while (!list_empty(&vmcore_list)) {
    1575                 :          0 :                 struct vmcore *m;
    1576                 :            : 
    1577                 :          0 :                 m = list_first_entry(&vmcore_list, struct vmcore, list);
    1578                 :          0 :                 list_del(&m->list);
    1579                 :          0 :                 kfree(m);
    1580                 :            :         }
    1581                 :          0 :         free_elfcorebuf();
    1582                 :            : 
    1583                 :            :         /* clear vmcore device dump list */
    1584                 :          0 :         vmcore_free_device_dumps();
    1585                 :          0 : }

Generated by: LCOV version 1.14