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/vmcore_info.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 34 struct 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 63 struct opalcore { 64 struct list_head list; 65 u64 paddr; 66 size_t size; 67 loff_t offset; 68 }; 69 70 static LIST_HEAD(opalcore_list); 71 static struct opalcore_config *oc_conf; 72 static const struct opal_mpipl_fadump *opalc_metadata; 73 static const struct opal_mpipl_fadump *opalc_cpu_metadata; 74 static 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 */ 80 bool kernel_initiated; 81 82 static struct opalcore * __init get_new_element(void) 83 { 84 return kzalloc(sizeof(struct opalcore), GFP_KERNEL); 85 } 86 87 static inline int is_opalcore_usable(void) 88 { 89 return (oc_conf && oc_conf->opalcorebuf != NULL) ? 1 : 0; 90 } 91 92 static Elf64_Word *__init 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 111 static void __init 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_regs(&(prstatus->pr_reg), regs); 116 117 /* 118 * Overload PID with PIR value. 119 * As a PIR value could also be '', 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 137 static Elf64_Word *__init 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 */ 161 static 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 209 static 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 */ 221 static 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, ®s); 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, ®s); 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 299 static 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 of_node_put(dn); 352 353 /* Use count to keep track of the program headers */ 354 count = 0; 355 356 bufp = oc_conf->opalcorebuf; 357 elf = (Elf64_Ehdr *)bufp; 358 bufp += sizeof(Elf64_Ehdr); 359 memcpy(elf->e_ident, ELFMAG, SELFMAG); 360 elf->e_ident[EI_CLASS] = ELF_CLASS; 361 elf->e_ident[EI_DATA] = ELFDATA2MSB; 362 elf->e_ident[EI_VERSION] = EV_CURRENT; 363 elf->e_ident[EI_OSABI] = ELF_OSABI; 364 memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); 365 elf->e_type = cpu_to_be16(ET_CORE); 366 elf->e_machine = cpu_to_be16(ELF_ARCH); 367 elf->e_version = cpu_to_be32(EV_CURRENT); 368 elf->e_entry = 0; 369 elf->e_phoff = cpu_to_be64(sizeof(Elf64_Ehdr)); 370 elf->e_shoff = 0; 371 elf->e_flags = 0; 372 373 elf->e_ehsize = cpu_to_be16(sizeof(Elf64_Ehdr)); 374 elf->e_phentsize = cpu_to_be16(sizeof(Elf64_Phdr)); 375 elf->e_phnum = 0; 376 elf->e_shentsize = 0; 377 elf->e_shnum = 0; 378 elf->e_shstrndx = 0; 379 380 phdr = (Elf64_Phdr *)bufp; 381 bufp += sizeof(Elf64_Phdr); 382 phdr->p_type = cpu_to_be32(PT_NOTE); 383 phdr->p_flags = 0; 384 phdr->p_align = 0; 385 phdr->p_paddr = phdr->p_vaddr = 0; 386 phdr->p_offset = cpu_to_be64(hdr_size); 387 phdr->p_filesz = phdr->p_memsz = cpu_to_be64(cpu_notes_size); 388 count++; 389 390 opalcore_off = oc_conf->opalcorebuf_sz; 391 oc_conf->ptload_phdr = (Elf64_Phdr *)bufp; 392 paddr = 0; 393 for (i = 0; i < oc_conf->ptload_cnt; i++) { 394 phdr = (Elf64_Phdr *)bufp; 395 bufp += sizeof(Elf64_Phdr); 396 phdr->p_type = cpu_to_be32(PT_LOAD); 397 phdr->p_flags = cpu_to_be32(PF_R|PF_W|PF_X); 398 phdr->p_align = 0; 399 400 new = get_new_element(); 401 if (!new) 402 return -ENOMEM; 403 new->paddr = oc_conf->ptload_addr[i]; 404 new->size = oc_conf->ptload_size[i]; 405 new->offset = opalcore_off; 406 list_add_tail(&new->list, &opalcore_list); 407 408 phdr->p_paddr = cpu_to_be64(paddr); 409 phdr->p_vaddr = cpu_to_be64(opal_base_addr + paddr); 410 phdr->p_filesz = phdr->p_memsz = 411 cpu_to_be64(oc_conf->ptload_size[i]); 412 phdr->p_offset = cpu_to_be64(opalcore_off); 413 414 count++; 415 opalcore_off += oc_conf->ptload_size[i]; 416 paddr += oc_conf->ptload_size[i]; 417 } 418 419 elf->e_phnum = cpu_to_be16(count); 420 421 bufp = (char *)opalcore_append_cpu_notes((Elf64_Word *)bufp); 422 bufp = (char *)auxv_to_elf64_notes((Elf64_Word *)bufp, opal_boot_entry); 423 424 oc_conf->opalcore_size = opalcore_off; 425 return 0; 426 } 427 428 static void opalcore_cleanup(void) 429 { 430 if (oc_conf == NULL) 431 return; 432 433 /* Remove OPAL core sysfs file */ 434 sysfs_remove_bin_file(mpipl_kobj, &opal_core_attr); 435 oc_conf->ptload_phdr = NULL; 436 oc_conf->ptload_cnt = 0; 437 438 /* free the buffer used for setting up OPAL core */ 439 if (oc_conf->opalcorebuf) { 440 void *end = (void *)((u64)oc_conf->opalcorebuf + 441 oc_conf->opalcorebuf_sz); 442 443 free_reserved_area(oc_conf->opalcorebuf, end, -1, NULL); 444 oc_conf->opalcorebuf = NULL; 445 oc_conf->opalcorebuf_sz = 0; 446 } 447 448 kfree(oc_conf); 449 oc_conf = NULL; 450 } 451 __exitcall(opalcore_cleanup); 452 453 static void __init opalcore_config_init(void) 454 { 455 u32 idx, cpu_data_version; 456 struct device_node *np; 457 const __be32 *prop; 458 u64 addr = 0; 459 int i, ret; 460 461 np = of_find_node_by_path("/ibm,opal/dump"); 462 if (np == NULL) 463 return; 464 465 if (!of_device_is_compatible(np, "ibm,opal-dump")) { 466 pr_warn("Support missing for this f/w version!\n"); 467 return; 468 } 469 470 /* Check if dump has been initiated on last reboot */ 471 prop = of_get_property(np, "mpipl-boot", NULL); 472 if (!prop) { 473 of_node_put(np); 474 return; 475 } 476 477 /* Get OPAL metadata */ 478 ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_OPAL, &addr); 479 if ((ret != OPAL_SUCCESS) || !addr) { 480 pr_err("Failed to get OPAL metadata (%d)\n", ret); 481 goto error_out; 482 } 483 484 addr = be64_to_cpu(addr); 485 pr_debug("OPAL metadata addr: %llx\n", addr); 486 opalc_metadata = __va(addr); 487 488 /* Get OPAL CPU metadata */ 489 ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_CPU, &addr); 490 if ((ret != OPAL_SUCCESS) || !addr) { 491 pr_err("Failed to get OPAL CPU metadata (%d)\n", ret); 492 goto error_out; 493 } 494 495 addr = be64_to_cpu(addr); 496 pr_debug("CPU metadata addr: %llx\n", addr); 497 opalc_cpu_metadata = __va(addr); 498 499 /* Allocate memory for config buffer */ 500 oc_conf = kzalloc(sizeof(struct opalcore_config), GFP_KERNEL); 501 if (oc_conf == NULL) 502 goto error_out; 503 504 /* Parse OPAL metadata */ 505 if (opalc_metadata->version != OPAL_MPIPL_VERSION) { 506 pr_warn("Supported OPAL metadata version: %u, found: %u!\n", 507 OPAL_MPIPL_VERSION, opalc_metadata->version); 508 pr_warn("WARNING: F/W using newer OPAL metadata format!!\n"); 509 } 510 511 oc_conf->ptload_cnt = 0; 512 idx = be32_to_cpu(opalc_metadata->region_cnt); 513 if (idx > MAX_PT_LOAD_CNT) { 514 pr_warn("WARNING: OPAL regions count (%d) adjusted to limit (%d)", 515 idx, MAX_PT_LOAD_CNT); 516 idx = MAX_PT_LOAD_CNT; 517 } 518 for (i = 0; i < idx; i++) { 519 oc_conf->ptload_addr[oc_conf->ptload_cnt] = 520 be64_to_cpu(opalc_metadata->region[i].dest); 521 oc_conf->ptload_size[oc_conf->ptload_cnt++] = 522 be64_to_cpu(opalc_metadata->region[i].size); 523 } 524 oc_conf->ptload_cnt = i; 525 oc_conf->crashing_cpu = be32_to_cpu(opalc_metadata->crashing_pir); 526 527 if (!oc_conf->ptload_cnt) { 528 pr_err("OPAL memory regions not found\n"); 529 goto error_out; 530 } 531 532 /* Parse OPAL CPU metadata */ 533 cpu_data_version = be32_to_cpu(opalc_cpu_metadata->cpu_data_version); 534 if (cpu_data_version != HDAT_FADUMP_CPU_DATA_VER) { 535 pr_warn("Supported CPU data version: %u, found: %u!\n", 536 HDAT_FADUMP_CPU_DATA_VER, cpu_data_version); 537 pr_warn("WARNING: F/W using newer CPU state data format!!\n"); 538 } 539 540 addr = be64_to_cpu(opalc_cpu_metadata->region[0].dest); 541 if (!addr) { 542 pr_err("CPU state data not found!\n"); 543 goto error_out; 544 } 545 oc_conf->cpu_state_destination_vaddr = (u64)__va(addr); 546 547 oc_conf->cpu_state_data_size = 548 be64_to_cpu(opalc_cpu_metadata->region[0].size); 549 oc_conf->cpu_state_entry_size = 550 be32_to_cpu(opalc_cpu_metadata->cpu_data_size); 551 552 if ((oc_conf->cpu_state_entry_size == 0) || 553 (oc_conf->cpu_state_entry_size > oc_conf->cpu_state_data_size)) { 554 pr_err("CPU state data is invalid.\n"); 555 goto error_out; 556 } 557 oc_conf->num_cpus = (oc_conf->cpu_state_data_size / 558 oc_conf->cpu_state_entry_size); 559 560 of_node_put(np); 561 return; 562 563 error_out: 564 pr_err("Could not export /sys/firmware/opal/core\n"); 565 opalcore_cleanup(); 566 of_node_put(np); 567 } 568 569 static ssize_t release_core_store(struct kobject *kobj, 570 struct kobj_attribute *attr, 571 const char *buf, size_t count) 572 { 573 int input = -1; 574 575 if (kstrtoint(buf, 0, &input)) 576 return -EINVAL; 577 578 if (input == 1) { 579 if (oc_conf == NULL) { 580 pr_err("'/sys/firmware/opal/core' file not accessible!\n"); 581 return -EPERM; 582 } 583 584 /* 585 * Take away '/sys/firmware/opal/core' and release all memory 586 * used for exporting this file. 587 */ 588 opalcore_cleanup(); 589 } else 590 return -EINVAL; 591 592 return count; 593 } 594 595 static struct kobj_attribute opalcore_rel_attr = __ATTR_WO(release_core); 596 597 static struct attribute *mpipl_attr[] = { 598 &opalcore_rel_attr.attr, 599 NULL, 600 }; 601 602 static struct bin_attribute *mpipl_bin_attr[] = { 603 &opal_core_attr, 604 NULL, 605 606 }; 607 608 static const struct attribute_group mpipl_group = { 609 .attrs = mpipl_attr, 610 .bin_attrs = mpipl_bin_attr, 611 }; 612 613 static int __init opalcore_init(void) 614 { 615 int rc = -1; 616 617 opalcore_config_init(); 618 619 if (oc_conf == NULL) 620 return rc; 621 622 create_opalcore(); 623 624 /* 625 * If oc_conf->opalcorebuf= is set in the 2nd kernel, 626 * then capture the dump. 627 */ 628 if (!(is_opalcore_usable())) { 629 pr_err("Failed to export /sys/firmware/opal/mpipl/core\n"); 630 opalcore_cleanup(); 631 return rc; 632 } 633 634 /* Set OPAL core file size */ 635 opal_core_attr.size = oc_conf->opalcore_size; 636 637 mpipl_kobj = kobject_create_and_add("mpipl", opal_kobj); 638 if (!mpipl_kobj) { 639 pr_err("unable to create mpipl kobject\n"); 640 return -ENOMEM; 641 } 642 643 /* Export OPAL core sysfs file */ 644 rc = sysfs_create_group(mpipl_kobj, &mpipl_group); 645 if (rc) { 646 pr_err("mpipl sysfs group creation failed (%d)", rc); 647 opalcore_cleanup(); 648 return rc; 649 } 650 /* The /sys/firmware/opal/core is moved to /sys/firmware/opal/mpipl/ 651 * directory, need to create symlink at old location to maintain 652 * backward compatibility. 653 */ 654 rc = compat_only_sysfs_link_entry_to_kobj(opal_kobj, mpipl_kobj, 655 "core", NULL); 656 if (rc) { 657 pr_err("unable to create core symlink (%d)\n", rc); 658 return rc; 659 } 660 661 return 0; 662 } 663 fs_initcall(opalcore_init); 664
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.