linux/arch/s390/kernel/crash_dump.c
<<
>>
Prefs
   1/*
   2 * S390 kdump implementation
   3 *
   4 * Copyright IBM Corp. 2011
   5 * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
   6 */
   7
   8#include <linux/crash_dump.h>
   9#include <asm/lowcore.h>
  10#include <linux/kernel.h>
  11#include <linux/module.h>
  12#include <linux/gfp.h>
  13#include <linux/slab.h>
  14#include <linux/bootmem.h>
  15#include <linux/elf.h>
  16#include <asm/os_info.h>
  17#include <asm/elf.h>
  18#include <asm/ipl.h>
  19#include <asm/sclp.h>
  20
  21#define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y)))
  22#define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
  23#define PTR_DIFF(x, y) ((unsigned long)(((char *) (x)) - ((unsigned long) (y))))
  24
  25
  26/*
  27 * Return physical address for virtual address
  28 */
  29static inline void *load_real_addr(void *addr)
  30{
  31        unsigned long real_addr;
  32
  33        asm volatile(
  34                   "    lra     %0,0(%1)\n"
  35                   "    jz      0f\n"
  36                   "    la      %0,0\n"
  37                   "0:"
  38                   : "=a" (real_addr) : "a" (addr) : "cc");
  39        return (void *)real_addr;
  40}
  41
  42/*
  43 * Copy real to virtual or real memory
  44 */
  45static int copy_from_realmem(void *dest, void *src, size_t count)
  46{
  47        unsigned long size;
  48        int rc;
  49
  50        if (!count)
  51                return 0;
  52        if (!is_vmalloc_or_module_addr(dest))
  53                return memcpy_real(dest, src, count);
  54        do {
  55                size = min(count, PAGE_SIZE - (__pa(dest) & ~PAGE_MASK));
  56                if (memcpy_real(load_real_addr(dest), src, size))
  57                        return -EFAULT;
  58                count -= size;
  59                dest += size;
  60                src += size;
  61        } while (count);
  62        return 0;
  63}
  64
  65/*
  66 * Pointer to ELF header in new kernel
  67 */
  68static void *elfcorehdr_newmem;
  69
  70/*
  71 * Copy one page from zfcpdump "oldmem"
  72 *
  73 * For pages below ZFCPDUMP_HSA_SIZE memory from the HSA is copied. Otherwise
  74 * real memory copy is used.
  75 */
  76static ssize_t copy_oldmem_page_zfcpdump(char *buf, size_t csize,
  77                                         unsigned long src, int userbuf)
  78{
  79        int rc;
  80
  81        if (src < ZFCPDUMP_HSA_SIZE) {
  82                rc = memcpy_hsa(buf, src, csize, userbuf);
  83        } else {
  84                if (userbuf)
  85                        rc = copy_to_user_real((void __force __user *) buf,
  86                                               (void *) src, csize);
  87                else
  88                        rc = memcpy_real(buf, (void *) src, csize);
  89        }
  90        return rc ? rc : csize;
  91}
  92
  93/*
  94 * Copy one page from kdump "oldmem"
  95 *
  96 * For the kdump reserved memory this functions performs a swap operation:
  97 *  - [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] is mapped to [0 - OLDMEM_SIZE].
  98 *  - [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
  99 */
 100static ssize_t copy_oldmem_page_kdump(char *buf, size_t csize,
 101                                      unsigned long src, int userbuf)
 102
 103{
 104        int rc;
 105
 106        if (src < OLDMEM_SIZE)
 107                src += OLDMEM_BASE;
 108        else if (src > OLDMEM_BASE &&
 109                 src < OLDMEM_BASE + OLDMEM_SIZE)
 110                src -= OLDMEM_BASE;
 111        if (userbuf)
 112                rc = copy_to_user_real((void __force __user *) buf,
 113                                       (void *) src, csize);
 114        else
 115                rc = copy_from_realmem(buf, (void *) src, csize);
 116        return (rc == 0) ? rc : csize;
 117}
 118
 119/*
 120 * Copy one page from "oldmem"
 121 */
 122ssize_t copy_oldmem_page(unsigned long pfn, char *buf, size_t csize,
 123                         unsigned long offset, int userbuf)
 124{
 125        unsigned long src;
 126
 127        if (!csize)
 128                return 0;
 129        src = (pfn << PAGE_SHIFT) + offset;
 130        if (OLDMEM_BASE)
 131                return copy_oldmem_page_kdump(buf, csize, src, userbuf);
 132        else
 133                return copy_oldmem_page_zfcpdump(buf, csize, src, userbuf);
 134}
 135
 136/*
 137 * Remap "oldmem" for kdump
 138 *
 139 * For the kdump reserved memory this functions performs a swap operation:
 140 * [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
 141 */
 142static int remap_oldmem_pfn_range_kdump(struct vm_area_struct *vma,
 143                                        unsigned long from, unsigned long pfn,
 144                                        unsigned long size, pgprot_t prot)
 145{
 146        unsigned long size_old;
 147        int rc;
 148
 149        if (pfn < OLDMEM_SIZE >> PAGE_SHIFT) {
 150                size_old = min(size, OLDMEM_SIZE - (pfn << PAGE_SHIFT));
 151                rc = remap_pfn_range(vma, from,
 152                                     pfn + (OLDMEM_BASE >> PAGE_SHIFT),
 153                                     size_old, prot);
 154                if (rc || size == size_old)
 155                        return rc;
 156                size -= size_old;
 157                from += size_old;
 158                pfn += size_old >> PAGE_SHIFT;
 159        }
 160        return remap_pfn_range(vma, from, pfn, size, prot);
 161}
 162
 163/*
 164 * Remap "oldmem" for zfcpdump
 165 *
 166 * We only map available memory above ZFCPDUMP_HSA_SIZE. Memory below
 167 * ZFCPDUMP_HSA_SIZE is read on demand using the copy_oldmem_page() function.
 168 */
 169static int remap_oldmem_pfn_range_zfcpdump(struct vm_area_struct *vma,
 170                                           unsigned long from,
 171                                           unsigned long pfn,
 172                                           unsigned long size, pgprot_t prot)
 173{
 174        unsigned long size_hsa;
 175
 176        if (pfn < ZFCPDUMP_HSA_SIZE >> PAGE_SHIFT) {
 177                size_hsa = min(size, ZFCPDUMP_HSA_SIZE - (pfn << PAGE_SHIFT));
 178                if (size == size_hsa)
 179                        return 0;
 180                size -= size_hsa;
 181                from += size_hsa;
 182                pfn += size_hsa >> PAGE_SHIFT;
 183        }
 184        return remap_pfn_range(vma, from, pfn, size, prot);
 185}
 186
 187/*
 188 * Remap "oldmem" for kdump or zfcpdump
 189 */
 190int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from,
 191                           unsigned long pfn, unsigned long size, pgprot_t prot)
 192{
 193        if (OLDMEM_BASE)
 194                return remap_oldmem_pfn_range_kdump(vma, from, pfn, size, prot);
 195        else
 196                return remap_oldmem_pfn_range_zfcpdump(vma, from, pfn, size,
 197                                                       prot);
 198}
 199
 200/*
 201 * Copy memory from old kernel
 202 */
 203int copy_from_oldmem(void *dest, void *src, size_t count)
 204{
 205        unsigned long copied = 0;
 206        int rc;
 207
 208        if (OLDMEM_BASE) {
 209                if ((unsigned long) src < OLDMEM_SIZE) {
 210                        copied = min(count, OLDMEM_SIZE - (unsigned long) src);
 211                        rc = copy_from_realmem(dest, src + OLDMEM_BASE, copied);
 212                        if (rc)
 213                                return rc;
 214                }
 215        } else {
 216                if ((unsigned long) src < ZFCPDUMP_HSA_SIZE) {
 217                        copied = min(count,
 218                                     ZFCPDUMP_HSA_SIZE - (unsigned long) src);
 219                        rc = memcpy_hsa(dest, (unsigned long) src, copied, 0);
 220                        if (rc)
 221                                return rc;
 222                }
 223        }
 224        return copy_from_realmem(dest + copied, src + copied, count - copied);
 225}
 226
 227/*
 228 * Alloc memory and panic in case of ENOMEM
 229 */
 230static void *kzalloc_panic(int len)
 231{
 232        void *rc;
 233
 234        rc = kzalloc(len, GFP_KERNEL);
 235        if (!rc)
 236                panic("s390 kdump kzalloc (%d) failed", len);
 237        return rc;
 238}
 239
 240/*
 241 * Get memory layout and create hole for oldmem
 242 */
 243static struct mem_chunk *get_memory_layout(void)
 244{
 245        struct mem_chunk *chunk_array;
 246
 247        chunk_array = kzalloc_panic(MEMORY_CHUNKS * sizeof(struct mem_chunk));
 248        detect_memory_layout(chunk_array, 0);
 249        create_mem_hole(chunk_array, OLDMEM_BASE, OLDMEM_SIZE);
 250        return chunk_array;
 251}
 252
 253/*
 254 * Initialize ELF note
 255 */
 256static void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len,
 257                     const char *name)
 258{
 259        Elf64_Nhdr *note;
 260        u64 len;
 261
 262        note = (Elf64_Nhdr *)buf;
 263        note->n_namesz = strlen(name) + 1;
 264        note->n_descsz = d_len;
 265        note->n_type = type;
 266        len = sizeof(Elf64_Nhdr);
 267
 268        memcpy(buf + len, name, note->n_namesz);
 269        len = roundup(len + note->n_namesz, 4);
 270
 271        memcpy(buf + len, desc, note->n_descsz);
 272        len = roundup(len + note->n_descsz, 4);
 273
 274        return PTR_ADD(buf, len);
 275}
 276
 277/*
 278 * Initialize prstatus note
 279 */
 280static void *nt_prstatus(void *ptr, struct save_area *sa)
 281{
 282        struct elf_prstatus nt_prstatus;
 283        static int cpu_nr = 1;
 284
 285        memset(&nt_prstatus, 0, sizeof(nt_prstatus));
 286        memcpy(&nt_prstatus.pr_reg.gprs, sa->gp_regs, sizeof(sa->gp_regs));
 287        memcpy(&nt_prstatus.pr_reg.psw, sa->psw, sizeof(sa->psw));
 288        memcpy(&nt_prstatus.pr_reg.acrs, sa->acc_regs, sizeof(sa->acc_regs));
 289        nt_prstatus.pr_pid = cpu_nr;
 290        cpu_nr++;
 291
 292        return nt_init(ptr, NT_PRSTATUS, &nt_prstatus, sizeof(nt_prstatus),
 293                         "CORE");
 294}
 295
 296/*
 297 * Initialize fpregset (floating point) note
 298 */
 299static void *nt_fpregset(void *ptr, struct save_area *sa)
 300{
 301        elf_fpregset_t nt_fpregset;
 302
 303        memset(&nt_fpregset, 0, sizeof(nt_fpregset));
 304        memcpy(&nt_fpregset.fpc, &sa->fp_ctrl_reg, sizeof(sa->fp_ctrl_reg));
 305        memcpy(&nt_fpregset.fprs, &sa->fp_regs, sizeof(sa->fp_regs));
 306
 307        return nt_init(ptr, NT_PRFPREG, &nt_fpregset, sizeof(nt_fpregset),
 308                       "CORE");
 309}
 310
 311/*
 312 * Initialize timer note
 313 */
 314static void *nt_s390_timer(void *ptr, struct save_area *sa)
 315{
 316        return nt_init(ptr, NT_S390_TIMER, &sa->timer, sizeof(sa->timer),
 317                         KEXEC_CORE_NOTE_NAME);
 318}
 319
 320/*
 321 * Initialize TOD clock comparator note
 322 */
 323static void *nt_s390_tod_cmp(void *ptr, struct save_area *sa)
 324{
 325        return nt_init(ptr, NT_S390_TODCMP, &sa->clk_cmp,
 326                       sizeof(sa->clk_cmp), KEXEC_CORE_NOTE_NAME);
 327}
 328
 329/*
 330 * Initialize TOD programmable register note
 331 */
 332static void *nt_s390_tod_preg(void *ptr, struct save_area *sa)
 333{
 334        return nt_init(ptr, NT_S390_TODPREG, &sa->tod_reg,
 335                       sizeof(sa->tod_reg), KEXEC_CORE_NOTE_NAME);
 336}
 337
 338/*
 339 * Initialize control register note
 340 */
 341static void *nt_s390_ctrs(void *ptr, struct save_area *sa)
 342{
 343        return nt_init(ptr, NT_S390_CTRS, &sa->ctrl_regs,
 344                       sizeof(sa->ctrl_regs), KEXEC_CORE_NOTE_NAME);
 345}
 346
 347/*
 348 * Initialize prefix register note
 349 */
 350static void *nt_s390_prefix(void *ptr, struct save_area *sa)
 351{
 352        return nt_init(ptr, NT_S390_PREFIX, &sa->pref_reg,
 353                         sizeof(sa->pref_reg), KEXEC_CORE_NOTE_NAME);
 354}
 355
 356/*
 357 * Fill ELF notes for one CPU with save area registers
 358 */
 359void *fill_cpu_elf_notes(void *ptr, struct save_area *sa)
 360{
 361        ptr = nt_prstatus(ptr, sa);
 362        ptr = nt_fpregset(ptr, sa);
 363        ptr = nt_s390_timer(ptr, sa);
 364        ptr = nt_s390_tod_cmp(ptr, sa);
 365        ptr = nt_s390_tod_preg(ptr, sa);
 366        ptr = nt_s390_ctrs(ptr, sa);
 367        ptr = nt_s390_prefix(ptr, sa);
 368        return ptr;
 369}
 370
 371/*
 372 * Initialize prpsinfo note (new kernel)
 373 */
 374static void *nt_prpsinfo(void *ptr)
 375{
 376        struct elf_prpsinfo prpsinfo;
 377
 378        memset(&prpsinfo, 0, sizeof(prpsinfo));
 379        prpsinfo.pr_sname = 'R';
 380        strcpy(prpsinfo.pr_fname, "vmlinux");
 381        return nt_init(ptr, NT_PRPSINFO, &prpsinfo, sizeof(prpsinfo),
 382                       KEXEC_CORE_NOTE_NAME);
 383}
 384
 385/*
 386 * Get vmcoreinfo using lowcore->vmcore_info (new kernel)
 387 */
 388static void *get_vmcoreinfo_old(unsigned long *size)
 389{
 390        char nt_name[11], *vmcoreinfo;
 391        Elf64_Nhdr note;
 392        void *addr;
 393
 394        if (copy_from_oldmem(&addr, &S390_lowcore.vmcore_info, sizeof(addr)))
 395                return NULL;
 396        memset(nt_name, 0, sizeof(nt_name));
 397        if (copy_from_oldmem(&note, addr, sizeof(note)))
 398                return NULL;
 399        if (copy_from_oldmem(nt_name, addr + sizeof(note), sizeof(nt_name) - 1))
 400                return NULL;
 401        if (strcmp(nt_name, "VMCOREINFO") != 0)
 402                return NULL;
 403        vmcoreinfo = kzalloc_panic(note.n_descsz);
 404        if (copy_from_oldmem(vmcoreinfo, addr + 24, note.n_descsz))
 405                return NULL;
 406        *size = note.n_descsz;
 407        return vmcoreinfo;
 408}
 409
 410/*
 411 * Initialize vmcoreinfo note (new kernel)
 412 */
 413static void *nt_vmcoreinfo(void *ptr)
 414{
 415        unsigned long size;
 416        void *vmcoreinfo;
 417
 418        vmcoreinfo = os_info_old_entry(OS_INFO_VMCOREINFO, &size);
 419        if (!vmcoreinfo)
 420                vmcoreinfo = get_vmcoreinfo_old(&size);
 421        if (!vmcoreinfo)
 422                return ptr;
 423        return nt_init(ptr, 0, vmcoreinfo, size, "VMCOREINFO");
 424}
 425
 426/*
 427 * Initialize ELF header (new kernel)
 428 */
 429static void *ehdr_init(Elf64_Ehdr *ehdr, int mem_chunk_cnt)
 430{
 431        memset(ehdr, 0, sizeof(*ehdr));
 432        memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
 433        ehdr->e_ident[EI_CLASS] = ELFCLASS64;
 434        ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
 435        ehdr->e_ident[EI_VERSION] = EV_CURRENT;
 436        memset(ehdr->e_ident + EI_PAD, 0, EI_NIDENT - EI_PAD);
 437        ehdr->e_type = ET_CORE;
 438        ehdr->e_machine = EM_S390;
 439        ehdr->e_version = EV_CURRENT;
 440        ehdr->e_phoff = sizeof(Elf64_Ehdr);
 441        ehdr->e_ehsize = sizeof(Elf64_Ehdr);
 442        ehdr->e_phentsize = sizeof(Elf64_Phdr);
 443        ehdr->e_phnum = mem_chunk_cnt + 1;
 444        return ehdr + 1;
 445}
 446
 447/*
 448 * Return CPU count for ELF header (new kernel)
 449 */
 450static int get_cpu_cnt(void)
 451{
 452        int i, cpus = 0;
 453
 454        for (i = 0; zfcpdump_save_areas[i]; i++) {
 455                if (zfcpdump_save_areas[i]->pref_reg == 0)
 456                        continue;
 457                cpus++;
 458        }
 459        return cpus;
 460}
 461
 462/*
 463 * Return memory chunk count for ELF header (new kernel)
 464 */
 465static int get_mem_chunk_cnt(void)
 466{
 467        struct mem_chunk *chunk_array, *mem_chunk;
 468        int i, cnt = 0;
 469
 470        chunk_array = get_memory_layout();
 471        for (i = 0; i < MEMORY_CHUNKS; i++) {
 472                mem_chunk = &chunk_array[i];
 473                if (chunk_array[i].type != CHUNK_READ_WRITE &&
 474                    chunk_array[i].type != CHUNK_READ_ONLY)
 475                        continue;
 476                if (mem_chunk->size == 0)
 477                        continue;
 478                cnt++;
 479        }
 480        kfree(chunk_array);
 481        return cnt;
 482}
 483
 484/*
 485 * Initialize ELF loads (new kernel)
 486 */
 487static int loads_init(Elf64_Phdr *phdr, u64 loads_offset)
 488{
 489        struct mem_chunk *chunk_array, *mem_chunk;
 490        int i;
 491
 492        chunk_array = get_memory_layout();
 493        for (i = 0; i < MEMORY_CHUNKS; i++) {
 494                mem_chunk = &chunk_array[i];
 495                if (mem_chunk->size == 0)
 496                        continue;
 497                if (chunk_array[i].type != CHUNK_READ_WRITE &&
 498                    chunk_array[i].type != CHUNK_READ_ONLY)
 499                        continue;
 500                else
 501                        phdr->p_filesz = mem_chunk->size;
 502                phdr->p_type = PT_LOAD;
 503                phdr->p_offset = mem_chunk->addr;
 504                phdr->p_vaddr = mem_chunk->addr;
 505                phdr->p_paddr = mem_chunk->addr;
 506                phdr->p_memsz = mem_chunk->size;
 507                phdr->p_flags = PF_R | PF_W | PF_X;
 508                phdr->p_align = PAGE_SIZE;
 509                phdr++;
 510        }
 511        kfree(chunk_array);
 512        return i;
 513}
 514
 515/*
 516 * Initialize notes (new kernel)
 517 */
 518static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
 519{
 520        struct save_area *sa;
 521        void *ptr_start = ptr;
 522        int i;
 523
 524        ptr = nt_prpsinfo(ptr);
 525
 526        for (i = 0; zfcpdump_save_areas[i]; i++) {
 527                sa = zfcpdump_save_areas[i];
 528                if (sa->pref_reg == 0)
 529                        continue;
 530                ptr = fill_cpu_elf_notes(ptr, sa);
 531        }
 532        ptr = nt_vmcoreinfo(ptr);
 533        memset(phdr, 0, sizeof(*phdr));
 534        phdr->p_type = PT_NOTE;
 535        phdr->p_offset = notes_offset;
 536        phdr->p_filesz = (unsigned long) PTR_SUB(ptr, ptr_start);
 537        phdr->p_memsz = phdr->p_filesz;
 538        return ptr;
 539}
 540
 541/*
 542 * Create ELF core header (new kernel)
 543 */
 544int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
 545{
 546        Elf64_Phdr *phdr_notes, *phdr_loads;
 547        int mem_chunk_cnt;
 548        void *ptr, *hdr;
 549        u32 alloc_size;
 550        u64 hdr_off;
 551
 552        /* If we are not in kdump or zfcpdump mode return */
 553        if (!OLDMEM_BASE && ipl_info.type != IPL_TYPE_FCP_DUMP)
 554                return 0;
 555        /* If elfcorehdr= has been passed via cmdline, we use that one */
 556        if (elfcorehdr_addr != ELFCORE_ADDR_MAX)
 557                return 0;
 558        mem_chunk_cnt = get_mem_chunk_cnt();
 559
 560        alloc_size = 0x1000 + get_cpu_cnt() * 0x300 +
 561                mem_chunk_cnt * sizeof(Elf64_Phdr);
 562        hdr = kzalloc_panic(alloc_size);
 563        /* Init elf header */
 564        ptr = ehdr_init(hdr, mem_chunk_cnt);
 565        /* Init program headers */
 566        phdr_notes = ptr;
 567        ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr));
 568        phdr_loads = ptr;
 569        ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr) * mem_chunk_cnt);
 570        /* Init notes */
 571        hdr_off = PTR_DIFF(ptr, hdr);
 572        ptr = notes_init(phdr_notes, ptr, ((unsigned long) hdr) + hdr_off);
 573        /* Init loads */
 574        hdr_off = PTR_DIFF(ptr, hdr);
 575        loads_init(phdr_loads, hdr_off);
 576        *addr = (unsigned long long) hdr;
 577        elfcorehdr_newmem = hdr;
 578        *size = (unsigned long long) hdr_off;
 579        BUG_ON(elfcorehdr_size > alloc_size);
 580        return 0;
 581}
 582
 583/*
 584 * Free ELF core header (new kernel)
 585 */
 586void elfcorehdr_free(unsigned long long addr)
 587{
 588        if (!elfcorehdr_newmem)
 589                return;
 590        kfree((void *)(unsigned long)addr);
 591}
 592
 593/*
 594 * Read from ELF header
 595 */
 596ssize_t elfcorehdr_read(char *buf, size_t count, u64 *ppos)
 597{
 598        void *src = (void *)(unsigned long)*ppos;
 599
 600        src = elfcorehdr_newmem ? src : src - OLDMEM_BASE;
 601        memcpy(buf, src, count);
 602        *ppos += count;
 603        return count;
 604}
 605
 606/*
 607 * Read from ELF notes data
 608 */
 609ssize_t elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos)
 610{
 611        void *src = (void *)(unsigned long)*ppos;
 612        int rc;
 613
 614        if (elfcorehdr_newmem) {
 615                memcpy(buf, src, count);
 616        } else {
 617                rc = copy_from_oldmem(buf, src, count);
 618                if (rc)
 619                        return rc;
 620        }
 621        *ppos += count;
 622        return count;
 623}
 624