linux/arch/powerpc/platforms/powernv/opal-core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Interface for exporting the OPAL ELF core.
   4 * Heavily inspired from fs/proc/vmcore.c
   5 *
   6 * Copyright 2019, Hari Bathini, IBM Corporation.
   7 */
   8
   9#define pr_fmt(fmt) "opal core: " fmt
  10
  11#include <linux/memblock.h>
  12#include <linux/uaccess.h>
  13#include <linux/proc_fs.h>
  14#include <linux/elf.h>
  15#include <linux/elfcore.h>
  16#include <linux/kobject.h>
  17#include <linux/sysfs.h>
  18#include <linux/slab.h>
  19#include <linux/crash_core.h>
  20#include <linux/of.h>
  21
  22#include <asm/page.h>
  23#include <asm/opal.h>
  24#include <asm/fadump-internal.h>
  25
  26#include "opal-fadump.h"
  27
  28#define MAX_PT_LOAD_CNT         8
  29
  30/* NT_AUXV note related info */
  31#define AUXV_CNT                1
  32#define AUXV_DESC_SZ            (((2 * AUXV_CNT) + 1) * sizeof(Elf64_Off))
  33
  34struct opalcore_config {
  35        u32                     num_cpus;
  36        /* PIR value of crashing CPU */
  37        u32                     crashing_cpu;
  38
  39        /* CPU state data info from F/W */
  40        u64                     cpu_state_destination_vaddr;
  41        u64                     cpu_state_data_size;
  42        u64                     cpu_state_entry_size;
  43
  44        /* OPAL memory to be exported as PT_LOAD segments */
  45        u64                     ptload_addr[MAX_PT_LOAD_CNT];
  46        u64                     ptload_size[MAX_PT_LOAD_CNT];
  47        u64                     ptload_cnt;
  48
  49        /* Pointer to the first PT_LOAD in the ELF core file */
  50        Elf64_Phdr              *ptload_phdr;
  51
  52        /* Total size of opalcore file. */
  53        size_t                  opalcore_size;
  54
  55        /* Buffer for all the ELF core headers and the PT_NOTE */
  56        size_t                  opalcorebuf_sz;
  57        char                    *opalcorebuf;
  58
  59        /* NT_AUXV buffer */
  60        char                    auxv_buf[AUXV_DESC_SZ];
  61};
  62
  63struct opalcore {
  64        struct list_head        list;
  65        u64                     paddr;
  66        size_t                  size;
  67        loff_t                  offset;
  68};
  69
  70static LIST_HEAD(opalcore_list);
  71static struct opalcore_config *oc_conf;
  72static const struct opal_mpipl_fadump *opalc_metadata;
  73static const struct opal_mpipl_fadump *opalc_cpu_metadata;
  74static struct kobject *mpipl_kobj;
  75
  76/*
  77 * Set crashing CPU's signal to SIGUSR1. if the kernel is triggered
  78 * by kernel, SIGTERM otherwise.
  79 */
  80bool kernel_initiated;
  81
  82static struct opalcore * __init get_new_element(void)
  83{
  84        return kzalloc(sizeof(struct opalcore), GFP_KERNEL);
  85}
  86
  87static inline int is_opalcore_usable(void)
  88{
  89        return (oc_conf && oc_conf->opalcorebuf != NULL) ? 1 : 0;
  90}
  91
  92static Elf64_Word *append_elf64_note(Elf64_Word *buf, char *name,
  93                                     u32 type, void *data,
  94                                     size_t data_len)
  95{
  96        Elf64_Nhdr *note = (Elf64_Nhdr *)buf;
  97        Elf64_Word namesz = strlen(name) + 1;
  98
  99        note->n_namesz = cpu_to_be32(namesz);
 100        note->n_descsz = cpu_to_be32(data_len);
 101        note->n_type   = cpu_to_be32(type);
 102        buf += DIV_ROUND_UP(sizeof(*note), sizeof(Elf64_Word));
 103        memcpy(buf, name, namesz);
 104        buf += DIV_ROUND_UP(namesz, sizeof(Elf64_Word));
 105        memcpy(buf, data, data_len);
 106        buf += DIV_ROUND_UP(data_len, sizeof(Elf64_Word));
 107
 108        return buf;
 109}
 110
 111static void fill_prstatus(struct elf_prstatus *prstatus, int pir,
 112                          struct pt_regs *regs)
 113{
 114        memset(prstatus, 0, sizeof(struct elf_prstatus));
 115        elf_core_copy_kernel_regs(&(prstatus->pr_reg), regs);
 116
 117        /*
 118         * Overload PID with PIR value.
 119         * As a PIR value could also be '0', add an offset of '100'
 120         * to every PIR to avoid misinterpretations in GDB.
 121         */
 122        prstatus->common.pr_pid  = cpu_to_be32(100 + pir);
 123        prstatus->common.pr_ppid = cpu_to_be32(1);
 124
 125        /*
 126         * Indicate SIGUSR1 for crash initiated from kernel.
 127         * SIGTERM otherwise.
 128         */
 129        if (pir == oc_conf->crashing_cpu) {
 130                short sig;
 131
 132                sig = kernel_initiated ? SIGUSR1 : SIGTERM;
 133                prstatus->common.pr_cursig = cpu_to_be16(sig);
 134        }
 135}
 136
 137static Elf64_Word *auxv_to_elf64_notes(Elf64_Word *buf,
 138                                       u64 opal_boot_entry)
 139{
 140        Elf64_Off *bufp = (Elf64_Off *)oc_conf->auxv_buf;
 141        int idx = 0;
 142
 143        memset(bufp, 0, AUXV_DESC_SZ);
 144
 145        /* Entry point of OPAL */
 146        bufp[idx++] = cpu_to_be64(AT_ENTRY);
 147        bufp[idx++] = cpu_to_be64(opal_boot_entry);
 148
 149        /* end of vector */
 150        bufp[idx++] = cpu_to_be64(AT_NULL);
 151
 152        buf = append_elf64_note(buf, CRASH_CORE_NOTE_NAME, NT_AUXV,
 153                                oc_conf->auxv_buf, AUXV_DESC_SZ);
 154        return buf;
 155}
 156
 157/*
 158 * Read from the ELF header and then the crash dump.
 159 * Returns number of bytes read on success, -errno on failure.
 160 */
 161static ssize_t read_opalcore(struct file *file, struct kobject *kobj,
 162                             struct bin_attribute *bin_attr, char *to,
 163                             loff_t pos, size_t count)
 164{
 165        struct opalcore *m;
 166        ssize_t tsz, avail;
 167        loff_t tpos = pos;
 168
 169        if (pos >= oc_conf->opalcore_size)
 170                return 0;
 171
 172        /* Adjust count if it goes beyond opalcore size */
 173        avail = oc_conf->opalcore_size - pos;
 174        if (count > avail)
 175                count = avail;
 176
 177        if (count == 0)
 178                return 0;
 179
 180        /* Read ELF core header and/or PT_NOTE segment */
 181        if (tpos < oc_conf->opalcorebuf_sz) {
 182                tsz = min_t(size_t, oc_conf->opalcorebuf_sz - tpos, count);
 183                memcpy(to, oc_conf->opalcorebuf + tpos, tsz);
 184                to += tsz;
 185                tpos += tsz;
 186                count -= tsz;
 187        }
 188
 189        list_for_each_entry(m, &opalcore_list, list) {
 190                /* nothing more to read here */
 191                if (count == 0)
 192                        break;
 193
 194                if (tpos < m->offset + m->size) {
 195                        void *addr;
 196
 197                        tsz = min_t(size_t, m->offset + m->size - tpos, count);
 198                        addr = (void *)(m->paddr + tpos - m->offset);
 199                        memcpy(to, __va(addr), tsz);
 200                        to += tsz;
 201                        tpos += tsz;
 202                        count -= tsz;
 203                }
 204        }
 205
 206        return (tpos - pos);
 207}
 208
 209static struct bin_attribute opal_core_attr = {
 210        .attr = {.name = "core", .mode = 0400},
 211        .read = read_opalcore
 212};
 213
 214/*
 215 * Read CPU state dump data and convert it into ELF notes.
 216 *
 217 * Each register entry is of 16 bytes, A numerical identifier along with
 218 * a GPR/SPR flag in the first 8 bytes and the register value in the next
 219 * 8 bytes. For more details refer to F/W documentation.
 220 */
 221static Elf64_Word * __init opalcore_append_cpu_notes(Elf64_Word *buf)
 222{
 223        u32 thread_pir, size_per_thread, regs_offset, regs_cnt, reg_esize;
 224        struct hdat_fadump_thread_hdr *thdr;
 225        struct elf_prstatus prstatus;
 226        Elf64_Word *first_cpu_note;
 227        struct pt_regs regs;
 228        char *bufp;
 229        int i;
 230
 231        size_per_thread = oc_conf->cpu_state_entry_size;
 232        bufp = __va(oc_conf->cpu_state_destination_vaddr);
 233
 234        /*
 235         * Offset for register entries, entry size and registers count is
 236         * duplicated in every thread header in keeping with HDAT format.
 237         * Use these values from the first thread header.
 238         */
 239        thdr = (struct hdat_fadump_thread_hdr *)bufp;
 240        regs_offset = (offsetof(struct hdat_fadump_thread_hdr, offset) +
 241                       be32_to_cpu(thdr->offset));
 242        reg_esize = be32_to_cpu(thdr->esize);
 243        regs_cnt  = be32_to_cpu(thdr->ecnt);
 244
 245        pr_debug("--------CPU State Data------------\n");
 246        pr_debug("NumCpus     : %u\n", oc_conf->num_cpus);
 247        pr_debug("\tOffset: %u, Entry size: %u, Cnt: %u\n",
 248                 regs_offset, reg_esize, regs_cnt);
 249
 250        /*
 251         * Skip past the first CPU note. Fill this note with the
 252         * crashing CPU's prstatus.
 253         */
 254        first_cpu_note = buf;
 255        buf = append_elf64_note(buf, CRASH_CORE_NOTE_NAME, NT_PRSTATUS,
 256                                &prstatus, sizeof(prstatus));
 257
 258        for (i = 0; i < oc_conf->num_cpus; i++, bufp += size_per_thread) {
 259                thdr = (struct hdat_fadump_thread_hdr *)bufp;
 260                thread_pir = be32_to_cpu(thdr->pir);
 261
 262                pr_debug("[%04d] PIR: 0x%x, core state: 0x%02x\n",
 263                         i, thread_pir, thdr->core_state);
 264
 265                /*
 266                 * Register state data of MAX cores is provided by firmware,
 267                 * but some of this cores may not be active. So, while
 268                 * processing register state data, check core state and
 269                 * skip threads that belong to inactive cores.
 270                 */
 271                if (thdr->core_state == HDAT_FADUMP_CORE_INACTIVE)
 272                        continue;
 273
 274                opal_fadump_read_regs((bufp + regs_offset), regs_cnt,
 275                                      reg_esize, false, &regs);
 276
 277                pr_debug("PIR 0x%x - R1 : 0x%llx, NIP : 0x%llx\n", thread_pir,
 278                         be64_to_cpu(regs.gpr[1]), be64_to_cpu(regs.nip));
 279                fill_prstatus(&prstatus, thread_pir, &regs);
 280
 281                if (thread_pir != oc_conf->crashing_cpu) {
 282                        buf = append_elf64_note(buf, CRASH_CORE_NOTE_NAME,
 283                                                NT_PRSTATUS, &prstatus,
 284                                                sizeof(prstatus));
 285                } else {
 286                        /*
 287                         * Add crashing CPU as the first NT_PRSTATUS note for
 288                         * GDB to process the core file appropriately.
 289                         */
 290                        append_elf64_note(first_cpu_note, CRASH_CORE_NOTE_NAME,
 291                                          NT_PRSTATUS, &prstatus,
 292                                          sizeof(prstatus));
 293                }
 294        }
 295
 296        return buf;
 297}
 298
 299static int __init create_opalcore(void)
 300{
 301        u64 opal_boot_entry, opal_base_addr, paddr;
 302        u32 hdr_size, cpu_notes_size, count;
 303        struct device_node *dn;
 304        struct opalcore *new;
 305        loff_t opalcore_off;
 306        struct page *page;
 307        Elf64_Phdr *phdr;
 308        Elf64_Ehdr *elf;
 309        int i, ret;
 310        char *bufp;
 311
 312        /* Get size of header & CPU notes for OPAL core */
 313        hdr_size = (sizeof(Elf64_Ehdr) +
 314                    ((oc_conf->ptload_cnt + 1) * sizeof(Elf64_Phdr)));
 315        cpu_notes_size = ((oc_conf->num_cpus * (CRASH_CORE_NOTE_HEAD_BYTES +
 316                          CRASH_CORE_NOTE_NAME_BYTES +
 317                          CRASH_CORE_NOTE_DESC_BYTES)) +
 318                          (CRASH_CORE_NOTE_HEAD_BYTES +
 319                          CRASH_CORE_NOTE_NAME_BYTES + AUXV_DESC_SZ));
 320
 321        /* Allocate buffer to setup OPAL core */
 322        oc_conf->opalcorebuf_sz = PAGE_ALIGN(hdr_size + cpu_notes_size);
 323        oc_conf->opalcorebuf = alloc_pages_exact(oc_conf->opalcorebuf_sz,
 324                                                 GFP_KERNEL | __GFP_ZERO);
 325        if (!oc_conf->opalcorebuf) {
 326                pr_err("Not enough memory to setup OPAL core (size: %lu)\n",
 327                       oc_conf->opalcorebuf_sz);
 328                oc_conf->opalcorebuf_sz = 0;
 329                return -ENOMEM;
 330        }
 331        count = oc_conf->opalcorebuf_sz / PAGE_SIZE;
 332        page = virt_to_page(oc_conf->opalcorebuf);
 333        for (i = 0; i < count; i++)
 334                mark_page_reserved(page + i);
 335
 336        pr_debug("opalcorebuf = 0x%llx\n", (u64)oc_conf->opalcorebuf);
 337
 338        /* Read OPAL related device-tree entries */
 339        dn = of_find_node_by_name(NULL, "ibm,opal");
 340        if (dn) {
 341                ret = of_property_read_u64(dn, "opal-base-address",
 342                                           &opal_base_addr);
 343                pr_debug("opal-base-address: %llx\n", opal_base_addr);
 344                ret |= of_property_read_u64(dn, "opal-boot-address",
 345                                            &opal_boot_entry);
 346                pr_debug("opal-boot-address: %llx\n", opal_boot_entry);
 347        }
 348        if (!dn || ret)
 349                pr_warn("WARNING: Failed to read OPAL base & entry values\n");
 350
 351        /* Use count to keep track of the program headers */
 352        count = 0;
 353
 354        bufp = oc_conf->opalcorebuf;
 355        elf = (Elf64_Ehdr *)bufp;
 356        bufp += sizeof(Elf64_Ehdr);
 357        memcpy(elf->e_ident, ELFMAG, SELFMAG);
 358        elf->e_ident[EI_CLASS] = ELF_CLASS;
 359        elf->e_ident[EI_DATA] = ELFDATA2MSB;
 360        elf->e_ident[EI_VERSION] = EV_CURRENT;
 361        elf->e_ident[EI_OSABI] = ELF_OSABI;
 362        memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
 363        elf->e_type = cpu_to_be16(ET_CORE);
 364        elf->e_machine = cpu_to_be16(ELF_ARCH);
 365        elf->e_version = cpu_to_be32(EV_CURRENT);
 366        elf->e_entry = 0;
 367        elf->e_phoff = cpu_to_be64(sizeof(Elf64_Ehdr));
 368        elf->e_shoff = 0;
 369        elf->e_flags = 0;
 370
 371        elf->e_ehsize = cpu_to_be16(sizeof(Elf64_Ehdr));
 372        elf->e_phentsize = cpu_to_be16(sizeof(Elf64_Phdr));
 373        elf->e_phnum = 0;
 374        elf->e_shentsize = 0;
 375        elf->e_shnum = 0;
 376        elf->e_shstrndx = 0;
 377
 378        phdr = (Elf64_Phdr *)bufp;
 379        bufp += sizeof(Elf64_Phdr);
 380        phdr->p_type    = cpu_to_be32(PT_NOTE);
 381        phdr->p_flags   = 0;
 382        phdr->p_align   = 0;
 383        phdr->p_paddr   = phdr->p_vaddr = 0;
 384        phdr->p_offset  = cpu_to_be64(hdr_size);
 385        phdr->p_filesz  = phdr->p_memsz = cpu_to_be64(cpu_notes_size);
 386        count++;
 387
 388        opalcore_off = oc_conf->opalcorebuf_sz;
 389        oc_conf->ptload_phdr  = (Elf64_Phdr *)bufp;
 390        paddr = 0;
 391        for (i = 0; i < oc_conf->ptload_cnt; i++) {
 392                phdr = (Elf64_Phdr *)bufp;
 393                bufp += sizeof(Elf64_Phdr);
 394                phdr->p_type    = cpu_to_be32(PT_LOAD);
 395                phdr->p_flags   = cpu_to_be32(PF_R|PF_W|PF_X);
 396                phdr->p_align   = 0;
 397
 398                new = get_new_element();
 399                if (!new)
 400                        return -ENOMEM;
 401                new->paddr  = oc_conf->ptload_addr[i];
 402                new->size   = oc_conf->ptload_size[i];
 403                new->offset = opalcore_off;
 404                list_add_tail(&new->list, &opalcore_list);
 405
 406                phdr->p_paddr   = cpu_to_be64(paddr);
 407                phdr->p_vaddr   = cpu_to_be64(opal_base_addr + paddr);
 408                phdr->p_filesz  = phdr->p_memsz  =
 409                        cpu_to_be64(oc_conf->ptload_size[i]);
 410                phdr->p_offset  = cpu_to_be64(opalcore_off);
 411
 412                count++;
 413                opalcore_off += oc_conf->ptload_size[i];
 414                paddr += oc_conf->ptload_size[i];
 415        }
 416
 417        elf->e_phnum = cpu_to_be16(count);
 418
 419        bufp = (char *)opalcore_append_cpu_notes((Elf64_Word *)bufp);
 420        bufp = (char *)auxv_to_elf64_notes((Elf64_Word *)bufp, opal_boot_entry);
 421
 422        oc_conf->opalcore_size = opalcore_off;
 423        return 0;
 424}
 425
 426static void opalcore_cleanup(void)
 427{
 428        if (oc_conf == NULL)
 429                return;
 430
 431        /* Remove OPAL core sysfs file */
 432        sysfs_remove_bin_file(mpipl_kobj, &opal_core_attr);
 433        oc_conf->ptload_phdr = NULL;
 434        oc_conf->ptload_cnt = 0;
 435
 436        /* free the buffer used for setting up OPAL core */
 437        if (oc_conf->opalcorebuf) {
 438                void *end = (void *)((u64)oc_conf->opalcorebuf +
 439                                     oc_conf->opalcorebuf_sz);
 440
 441                free_reserved_area(oc_conf->opalcorebuf, end, -1, NULL);
 442                oc_conf->opalcorebuf = NULL;
 443                oc_conf->opalcorebuf_sz = 0;
 444        }
 445
 446        kfree(oc_conf);
 447        oc_conf = NULL;
 448}
 449__exitcall(opalcore_cleanup);
 450
 451static void __init opalcore_config_init(void)
 452{
 453        u32 idx, cpu_data_version;
 454        struct device_node *np;
 455        const __be32 *prop;
 456        u64 addr = 0;
 457        int i, ret;
 458
 459        np = of_find_node_by_path("/ibm,opal/dump");
 460        if (np == NULL)
 461                return;
 462
 463        if (!of_device_is_compatible(np, "ibm,opal-dump")) {
 464                pr_warn("Support missing for this f/w version!\n");
 465                return;
 466        }
 467
 468        /* Check if dump has been initiated on last reboot */
 469        prop = of_get_property(np, "mpipl-boot", NULL);
 470        if (!prop) {
 471                of_node_put(np);
 472                return;
 473        }
 474
 475        /* Get OPAL metadata */
 476        ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_OPAL, &addr);
 477        if ((ret != OPAL_SUCCESS) || !addr) {
 478                pr_err("Failed to get OPAL metadata (%d)\n", ret);
 479                goto error_out;
 480        }
 481
 482        addr = be64_to_cpu(addr);
 483        pr_debug("OPAL metadata addr: %llx\n", addr);
 484        opalc_metadata = __va(addr);
 485
 486        /* Get OPAL CPU metadata */
 487        ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_CPU, &addr);
 488        if ((ret != OPAL_SUCCESS) || !addr) {
 489                pr_err("Failed to get OPAL CPU metadata (%d)\n", ret);
 490                goto error_out;
 491        }
 492
 493        addr = be64_to_cpu(addr);
 494        pr_debug("CPU metadata addr: %llx\n", addr);
 495        opalc_cpu_metadata = __va(addr);
 496
 497        /* Allocate memory for config buffer */
 498        oc_conf = kzalloc(sizeof(struct opalcore_config), GFP_KERNEL);
 499        if (oc_conf == NULL)
 500                goto error_out;
 501
 502        /* Parse OPAL metadata */
 503        if (opalc_metadata->version != OPAL_MPIPL_VERSION) {
 504                pr_warn("Supported OPAL metadata version: %u, found: %u!\n",
 505                        OPAL_MPIPL_VERSION, opalc_metadata->version);
 506                pr_warn("WARNING: F/W using newer OPAL metadata format!!\n");
 507        }
 508
 509        oc_conf->ptload_cnt = 0;
 510        idx = be32_to_cpu(opalc_metadata->region_cnt);
 511        if (idx > MAX_PT_LOAD_CNT) {
 512                pr_warn("WARNING: OPAL regions count (%d) adjusted to limit (%d)",
 513                        idx, MAX_PT_LOAD_CNT);
 514                idx = MAX_PT_LOAD_CNT;
 515        }
 516        for (i = 0; i < idx; i++) {
 517                oc_conf->ptload_addr[oc_conf->ptload_cnt] =
 518                                be64_to_cpu(opalc_metadata->region[i].dest);
 519                oc_conf->ptload_size[oc_conf->ptload_cnt++] =
 520                                be64_to_cpu(opalc_metadata->region[i].size);
 521        }
 522        oc_conf->ptload_cnt = i;
 523        oc_conf->crashing_cpu = be32_to_cpu(opalc_metadata->crashing_pir);
 524
 525        if (!oc_conf->ptload_cnt) {
 526                pr_err("OPAL memory regions not found\n");
 527                goto error_out;
 528        }
 529
 530        /* Parse OPAL CPU metadata */
 531        cpu_data_version = be32_to_cpu(opalc_cpu_metadata->cpu_data_version);
 532        if (cpu_data_version != HDAT_FADUMP_CPU_DATA_VER) {
 533                pr_warn("Supported CPU data version: %u, found: %u!\n",
 534                        HDAT_FADUMP_CPU_DATA_VER, cpu_data_version);
 535                pr_warn("WARNING: F/W using newer CPU state data format!!\n");
 536        }
 537
 538        addr = be64_to_cpu(opalc_cpu_metadata->region[0].dest);
 539        if (!addr) {
 540                pr_err("CPU state data not found!\n");
 541                goto error_out;
 542        }
 543        oc_conf->cpu_state_destination_vaddr = (u64)__va(addr);
 544
 545        oc_conf->cpu_state_data_size =
 546                        be64_to_cpu(opalc_cpu_metadata->region[0].size);
 547        oc_conf->cpu_state_entry_size =
 548                        be32_to_cpu(opalc_cpu_metadata->cpu_data_size);
 549
 550        if ((oc_conf->cpu_state_entry_size == 0) ||
 551            (oc_conf->cpu_state_entry_size > oc_conf->cpu_state_data_size)) {
 552                pr_err("CPU state data is invalid.\n");
 553                goto error_out;
 554        }
 555        oc_conf->num_cpus = (oc_conf->cpu_state_data_size /
 556                             oc_conf->cpu_state_entry_size);
 557
 558        of_node_put(np);
 559        return;
 560
 561error_out:
 562        pr_err("Could not export /sys/firmware/opal/core\n");
 563        opalcore_cleanup();
 564        of_node_put(np);
 565}
 566
 567static ssize_t release_core_store(struct kobject *kobj,
 568                                  struct kobj_attribute *attr,
 569                                  const char *buf, size_t count)
 570{
 571        int input = -1;
 572
 573        if (kstrtoint(buf, 0, &input))
 574                return -EINVAL;
 575
 576        if (input == 1) {
 577                if (oc_conf == NULL) {
 578                        pr_err("'/sys/firmware/opal/core' file not accessible!\n");
 579                        return -EPERM;
 580                }
 581
 582                /*
 583                 * Take away '/sys/firmware/opal/core' and release all memory
 584                 * used for exporting this file.
 585                 */
 586                opalcore_cleanup();
 587        } else
 588                return -EINVAL;
 589
 590        return count;
 591}
 592
 593static struct kobj_attribute opalcore_rel_attr = __ATTR_WO(release_core);
 594
 595static struct attribute *mpipl_attr[] = {
 596        &opalcore_rel_attr.attr,
 597        NULL,
 598};
 599
 600static struct bin_attribute *mpipl_bin_attr[] = {
 601        &opal_core_attr,
 602        NULL,
 603
 604};
 605
 606static struct attribute_group mpipl_group = {
 607        .attrs = mpipl_attr,
 608        .bin_attrs =  mpipl_bin_attr,
 609};
 610
 611static int __init opalcore_init(void)
 612{
 613        int rc = -1;
 614
 615        opalcore_config_init();
 616
 617        if (oc_conf == NULL)
 618                return rc;
 619
 620        create_opalcore();
 621
 622        /*
 623         * If oc_conf->opalcorebuf= is set in the 2nd kernel,
 624         * then capture the dump.
 625         */
 626        if (!(is_opalcore_usable())) {
 627                pr_err("Failed to export /sys/firmware/opal/mpipl/core\n");
 628                opalcore_cleanup();
 629                return rc;
 630        }
 631
 632        /* Set OPAL core file size */
 633        opal_core_attr.size = oc_conf->opalcore_size;
 634
 635        mpipl_kobj = kobject_create_and_add("mpipl", opal_kobj);
 636        if (!mpipl_kobj) {
 637                pr_err("unable to create mpipl kobject\n");
 638                return -ENOMEM;
 639        }
 640
 641        /* Export OPAL core sysfs file */
 642        rc = sysfs_create_group(mpipl_kobj, &mpipl_group);
 643        if (rc) {
 644                pr_err("mpipl sysfs group creation failed (%d)", rc);
 645                opalcore_cleanup();
 646                return rc;
 647        }
 648        /* The /sys/firmware/opal/core is moved to /sys/firmware/opal/mpipl/
 649         * directory, need to create symlink at old location to maintain
 650         * backward compatibility.
 651         */
 652        rc = compat_only_sysfs_link_entry_to_kobj(opal_kobj, mpipl_kobj,
 653                                                  "core", NULL);
 654        if (rc) {
 655                pr_err("unable to create core symlink (%d)\n", rc);
 656                return rc;
 657        }
 658
 659        return 0;
 660}
 661fs_initcall(opalcore_init);
 662