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