/* * Overload PID with PIR value. * As a PIR value could also be '0', add an offset of '100' * to every PIR to avoid misinterpretations in GDB.
*/
prstatus->common.pr_pid = cpu_to_be32(100 + pir);
prstatus->common.pr_ppid = cpu_to_be32(1);
/* * Indicate SIGUSR1 for crash initiated from kernel. * SIGTERM otherwise.
*/ if (pir == oc_conf->crashing_cpu) { short sig;
/* * Read CPU state dump data and convert it into ELF notes. * * Each register entry is of 16 bytes, A numerical identifier along with * a GPR/SPR flag in the first 8 bytes and the register value in the next * 8 bytes. For more details refer to F/W documentation.
*/ static Elf64_Word * __init opalcore_append_cpu_notes(Elf64_Word *buf)
{
u32 thread_pir, size_per_thread, regs_offset, regs_cnt, reg_esize; struct hdat_fadump_thread_hdr *thdr; struct elf_prstatus prstatus;
Elf64_Word *first_cpu_note; struct pt_regs regs; char *bufp; int i;
/* * Offset for register entries, entry size and registers count is * duplicated in every thread header in keeping with HDAT format. * Use these values from the first thread header.
*/
thdr = (struct hdat_fadump_thread_hdr *)bufp;
regs_offset = (offsetof(struct hdat_fadump_thread_hdr, offset) +
be32_to_cpu(thdr->offset));
reg_esize = be32_to_cpu(thdr->esize);
regs_cnt = be32_to_cpu(thdr->ecnt);
/* * Skip past the first CPU note. Fill this note with the * crashing CPU's prstatus.
*/
first_cpu_note = buf;
buf = append_elf64_note(buf, NN_PRSTATUS, NT_PRSTATUS,
&prstatus, sizeof(prstatus));
for (i = 0; i < oc_conf->num_cpus; i++, bufp += size_per_thread) {
thdr = (struct hdat_fadump_thread_hdr *)bufp;
thread_pir = be32_to_cpu(thdr->pir);
pr_debug("[%04d] PIR: 0x%x, core state: 0x%02x\n",
i, thread_pir, thdr->core_state);
/* * Register state data of MAX cores is provided by firmware, * but some of this cores may not be active. So, while * processing register state data, check core state and * skip threads that belong to inactive cores.
*/ if (thdr->core_state == HDAT_FADUMP_CORE_INACTIVE) continue;
if (thread_pir != oc_conf->crashing_cpu) {
buf = append_elf64_note(buf, NN_PRSTATUS,
NT_PRSTATUS, &prstatus, sizeof(prstatus));
} else { /* * Add crashing CPU as the first NT_PRSTATUS note for * GDB to process the core file appropriately.
*/
append_elf64_note(first_cpu_note, NN_PRSTATUS,
NT_PRSTATUS, &prstatus, sizeof(prstatus));
}
}
/* free the buffer used for setting up OPAL core */ if (oc_conf->opalcorebuf) { void *end = (void *)((u64)oc_conf->opalcorebuf +
oc_conf->opalcorebuf_sz);
/* Get OPAL CPU metadata */
ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_CPU, &addr); if ((ret != OPAL_SUCCESS) || !addr) {
pr_err("Failed to get OPAL CPU metadata (%d)\n", ret); goto error_out;
}
oc_conf->ptload_cnt = 0;
idx = be32_to_cpu(opalc_metadata->region_cnt); if (idx > MAX_PT_LOAD_CNT) {
pr_warn("WARNING: OPAL regions count (%d) adjusted to limit (%d)",
idx, MAX_PT_LOAD_CNT);
idx = MAX_PT_LOAD_CNT;
} for (i = 0; i < idx; i++) {
oc_conf->ptload_addr[oc_conf->ptload_cnt] =
be64_to_cpu(opalc_metadata->region[i].dest);
oc_conf->ptload_size[oc_conf->ptload_cnt++] =
be64_to_cpu(opalc_metadata->region[i].size);
}
oc_conf->ptload_cnt = i;
oc_conf->crashing_cpu = be32_to_cpu(opalc_metadata->crashing_pir);
if (!oc_conf->ptload_cnt) {
pr_err("OPAL memory regions not found\n"); goto error_out;
}
/* Parse OPAL CPU metadata */
cpu_data_version = be32_to_cpu(opalc_cpu_metadata->cpu_data_version); if (cpu_data_version != HDAT_FADUMP_CPU_DATA_VER) {
pr_warn("Supported CPU data version: %u, found: %u!\n",
HDAT_FADUMP_CPU_DATA_VER, cpu_data_version);
pr_warn("WARNING: F/W using newer CPU state data format!!\n");
}
addr = be64_to_cpu(opalc_cpu_metadata->region[0].dest); if (!addr) {
pr_err("CPU state data not found!\n"); goto error_out;
}
oc_conf->cpu_state_destination_vaddr = (u64)__va(addr);
staticint __init opalcore_init(void)
{ int rc = -1;
opalcore_config_init();
if (oc_conf == NULL) return rc;
create_opalcore();
/* * If oc_conf->opalcorebuf= is set in the 2nd kernel, * then capture the dump.
*/ if (!(is_opalcore_usable())) {
pr_err("Failed to export /sys/firmware/opal/mpipl/core\n");
opalcore_cleanup(); return rc;
}
/* Set OPAL core file size */
opal_core_attr.size = oc_conf->opalcore_size;
mpipl_kobj = kobject_create_and_add("mpipl", opal_kobj); if (!mpipl_kobj) {
pr_err("unable to create mpipl kobject\n"); return -ENOMEM;
}
/* Export OPAL core sysfs file */
rc = sysfs_create_group(mpipl_kobj, &mpipl_group); if (rc) {
pr_err("mpipl sysfs group creation failed (%d)", rc);
opalcore_cleanup(); return rc;
} /* The /sys/firmware/opal/core is moved to /sys/firmware/opal/mpipl/ * directory, need to create symlink at old location to maintain * backward compatibility.
*/
rc = compat_only_sysfs_link_entry_to_kobj(opal_kobj, mpipl_kobj, "core", NULL); if (rc) {
pr_err("unable to create core symlink (%d)\n", rc); return rc;
}
return 0;
}
fs_initcall(opalcore_init);
Messung V0.5
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.