Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

powerpc: make fadump resilient with memory add/remove events

Due to changes in memory resources caused by either memory hotplug or
online/offline events, the elfcorehdr, which describes the CPUs and
memory of the crashed kernel to the kernel that collects the dump (known
as second/fadump kernel), becomes outdated. Consequently, attempting
dump collection with an outdated elfcorehdr can lead to failed or
inaccurate dump collection.

Memory hotplug or online/offline events is referred as memory add/remove
events in reset of the commit message.

The current solution to address the aforementioned issue is as follows:
Monitor memory add/remove events in userspace using udev rules, and
re-register fadump whenever there are changes in memory resources. This
leads to the creation of a new elfcorehdr with updated system memory
information.

There are several notable issues associated with re-registering fadump
for every memory add/remove events.

1. Bulk memory add/remove events with udev-based fadump re-registration
can lead to race conditions and, more importantly, it creates a wide
window during which fadump is inactive until all memory add/remove
events are settled.
2. Re-registering fadump for every memory add/remove event is
inefficient.
3. The memory for elfcorehdr is allocated based on the memblock regions
available during early boot and remains fixed thereafter. However, if
elfcorehdr is later recreated with additional memblock regions, its
size will increase, potentially leading to memory corruption.

Address the aforementioned challenges by shifting the creation of
elfcorehdr from the first kernel (also referred as the crashed kernel),
where it was created and frequently recreated for every memory
add/remove event, to the fadump kernel. As a result, the elfcorehdr only
needs to be created once, thus eliminating the necessity to re-register
fadump during memory add/remove events.

At present, the first kernel prepares fadump header and stores it in the
fadump reserved area. The fadump header includes the start address of
the elfcorehdr, crashing CPU details, and other relevant information. In
the event of a crash in the first kernel, the second/fadump boots and
accesses the fadump header prepared by the first kernel. It then
performs the following steps in a platform-specific function
[rtas|opal]_fadump_process:

1. Sanity check for fadump header
2. Update CPU notes in elfcorehdr

Along with the above, update the setup_fadump()/fadump.c to create
elfcorehdr and set its address to the global variable elfcorehdr_addr
for the vmcore module to process it in the second/fadump kernel.

Section below outlines the information required to create the elfcorehdr
and the changes made to make it available to the fadump kernel if it's
not already.

To create elfcorehdr, the following crashed kernel information is
required: CPU notes, vmcoreinfo, and memory ranges.

At present, the CPU notes are already prepared in the fadump kernel, so
no changes are needed in that regard. The fadump kernel has access to
all crashed kernel memory regions, including boot memory regions that
are relocated by firmware to fadump reserved areas, so no changes for
that either. However, it is necessary to add new members to the fadump
header, i.e., the 'fadump_crash_info_header' structure, in order to pass
the crashed kernel's vmcoreinfo address and its size to fadump kernel.

In addition to the vmcoreinfo address and size, there are a few other
attributes also added to the fadump_crash_info_header structure.

1. version:
It stores the fadump header version, which is currently set to 1.
This provides flexibility to update the fadump crash info header in
the future without changing the magic number. For each change in the
fadump header, the version will be increased. This will help the
updated kernel determine how to handle kernel dumps from older
kernels. The magic number remains relevant for checking fadump header
corruption.

2. pt_regs_sz/cpu_mask_sz:
Store size of pt_regs and cpu_mask structure of first kernel. These
attributes are used to prevent dump processing if the sizes of
pt_regs or cpu_mask structure differ between the first and fadump
kernels.

Note: if either first/crashed kernel or second/fadump kernel do not have
the changes introduced here then kernel fail to collect the dump and
prints relevant error message on the console.

Signed-off-by: Sourabh Jain <sourabhjain@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20240422195932.1583833-2-sourabhjain@linux.ibm.com

authored by

Sourabh Jain and committed by
Michael Ellerman
c6c5b14d 6d434163

+242 -206
+29 -2
arch/powerpc/include/asm/fadump-internal.h
··· 42 42 43 43 #define FADUMP_CPU_UNKNOWN (~((u32)0)) 44 44 45 - #define FADUMP_CRASH_INFO_MAGIC fadump_str_to_u64("FADMPINF") 45 + /* 46 + * The introduction of new fields in the fadump crash info header has 47 + * led to a change in the magic key from `FADMPINF` to `FADMPSIG` for 48 + * identifying a kernel crash from an old kernel. 49 + * 50 + * To prevent the need for further changes to the magic number in the 51 + * event of future modifications to the fadump crash info header, a 52 + * version field has been introduced to track the fadump crash info 53 + * header version. 54 + * 55 + * Consider a few points before adding new members to the fadump crash info 56 + * header structure: 57 + * 58 + * - Append new members; avoid adding them in between. 59 + * - Non-primitive members should have a size member as well. 60 + * - For every change in the fadump header, increment the 61 + * fadump header version. This helps the updated kernel decide how to 62 + * handle kernel dumps from older kernels. 63 + */ 64 + #define FADUMP_CRASH_INFO_MAGIC_OLD fadump_str_to_u64("FADMPINF") 65 + #define FADUMP_CRASH_INFO_MAGIC fadump_str_to_u64("FADMPSIG") 66 + #define FADUMP_HEADER_VERSION 1 46 67 47 68 /* fadump crash info structure */ 48 69 struct fadump_crash_info_header { 49 70 u64 magic_number; 50 - u64 elfcorehdr_addr; 71 + u32 version; 51 72 u32 crashing_cpu; 73 + u64 vmcoreinfo_raddr; 74 + u64 vmcoreinfo_size; 75 + u32 pt_regs_sz; 76 + u32 cpu_mask_sz; 52 77 struct pt_regs regs; 53 78 struct cpumask cpu_mask; 54 79 }; ··· 119 94 u64 boot_mem_regs_cnt; 120 95 121 96 unsigned long fadumphdr_addr; 97 + u64 elfcorehdr_addr; 98 + u64 elfcorehdr_size; 122 99 unsigned long cpu_notes_buf_vaddr; 123 100 unsigned long cpu_notes_buf_size; 124 101
+205 -156
arch/powerpc/kernel/fadump.c
··· 53 53 static atomic_t cpus_in_fadump; 54 54 static DEFINE_MUTEX(fadump_mutex); 55 55 56 - static struct fadump_mrange_info crash_mrange_info = { "crash", NULL, 0, 0, 0, false }; 57 - 58 56 #define RESERVED_RNGS_SZ 16384 /* 16K - 128 entries */ 59 57 #define RESERVED_RNGS_CNT (RESERVED_RNGS_SZ / \ 60 58 sizeof(struct fadump_memory_range)) ··· 371 373 size = PAGE_ALIGN(size); 372 374 size += fw_dump.boot_memory_size; 373 375 size += sizeof(struct fadump_crash_info_header); 374 - size += sizeof(struct elfhdr); /* ELF core header.*/ 375 - size += sizeof(struct elf_phdr); /* place holder for cpu notes */ 376 - /* Program headers for crash memory regions. */ 377 - size += sizeof(struct elf_phdr) * (memblock_num_regions(memory) + 2); 378 - 379 - size = PAGE_ALIGN(size); 380 376 381 377 /* This is to hold kernel metadata on platforms that support it */ 382 378 size += (fw_dump.ops->fadump_get_metadata_size ? ··· 907 915 return 0; 908 916 } 909 917 910 - static int fadump_exclude_reserved_area(u64 start, u64 end) 911 - { 912 - u64 ra_start, ra_end; 913 - int ret = 0; 914 - 915 - ra_start = fw_dump.reserve_dump_area_start; 916 - ra_end = ra_start + fw_dump.reserve_dump_area_size; 917 - 918 - if ((ra_start < end) && (ra_end > start)) { 919 - if ((start < ra_start) && (end > ra_end)) { 920 - ret = fadump_add_mem_range(&crash_mrange_info, 921 - start, ra_start); 922 - if (ret) 923 - return ret; 924 - 925 - ret = fadump_add_mem_range(&crash_mrange_info, 926 - ra_end, end); 927 - } else if (start < ra_start) { 928 - ret = fadump_add_mem_range(&crash_mrange_info, 929 - start, ra_start); 930 - } else if (ra_end < end) { 931 - ret = fadump_add_mem_range(&crash_mrange_info, 932 - ra_end, end); 933 - } 934 - } else 935 - ret = fadump_add_mem_range(&crash_mrange_info, start, end); 936 - 937 - return ret; 938 - } 939 - 940 918 static int fadump_init_elfcore_header(char *bufp) 941 919 { 942 920 struct elfhdr *elf; ··· 944 982 } 945 983 946 984 /* 947 - * Traverse through memblock structure and setup crash memory ranges. These 948 - * ranges will be used create PT_LOAD program headers in elfcore header. 949 - */ 950 - static int fadump_setup_crash_memory_ranges(void) 951 - { 952 - u64 i, start, end; 953 - int ret; 954 - 955 - pr_debug("Setup crash memory ranges.\n"); 956 - crash_mrange_info.mem_range_cnt = 0; 957 - 958 - /* 959 - * Boot memory region(s) registered with firmware are moved to 960 - * different location at the time of crash. Create separate program 961 - * header(s) for this memory chunk(s) with the correct offset. 962 - */ 963 - for (i = 0; i < fw_dump.boot_mem_regs_cnt; i++) { 964 - start = fw_dump.boot_mem_addr[i]; 965 - end = start + fw_dump.boot_mem_sz[i]; 966 - ret = fadump_add_mem_range(&crash_mrange_info, start, end); 967 - if (ret) 968 - return ret; 969 - } 970 - 971 - for_each_mem_range(i, &start, &end) { 972 - /* 973 - * skip the memory chunk that is already added 974 - * (0 through boot_memory_top). 975 - */ 976 - if (start < fw_dump.boot_mem_top) { 977 - if (end > fw_dump.boot_mem_top) 978 - start = fw_dump.boot_mem_top; 979 - else 980 - continue; 981 - } 982 - 983 - /* add this range excluding the reserved dump area. */ 984 - ret = fadump_exclude_reserved_area(start, end); 985 - if (ret) 986 - return ret; 987 - } 988 - 989 - return 0; 990 - } 991 - 992 - /* 993 985 * If the given physical address falls within the boot memory region then 994 986 * return the relocated address that points to the dump region reserved 995 987 * for saving initial boot memory contents. ··· 973 1057 return raddr; 974 1058 } 975 1059 976 - static int fadump_create_elfcore_headers(char *bufp) 1060 + static void __init populate_elf_pt_load(struct elf_phdr *phdr, u64 start, 1061 + u64 size, unsigned long long offset) 977 1062 { 978 - unsigned long long raddr, offset; 979 - struct elf_phdr *phdr; 980 - struct elfhdr *elf; 981 - int i, j; 1063 + phdr->p_align = 0; 1064 + phdr->p_memsz = size; 1065 + phdr->p_filesz = size; 1066 + phdr->p_paddr = start; 1067 + phdr->p_offset = offset; 1068 + phdr->p_type = PT_LOAD; 1069 + phdr->p_flags = PF_R|PF_W|PF_X; 1070 + phdr->p_vaddr = (unsigned long)__va(start); 1071 + } 982 1072 1073 + static void __init fadump_populate_elfcorehdr(struct fadump_crash_info_header *fdh) 1074 + { 1075 + char *bufp; 1076 + struct elfhdr *elf; 1077 + struct elf_phdr *phdr; 1078 + u64 boot_mem_dest_offset; 1079 + unsigned long long i, ra_start, ra_end, ra_size, mstart, mend; 1080 + 1081 + bufp = (char *) fw_dump.elfcorehdr_addr; 983 1082 fadump_init_elfcore_header(bufp); 984 1083 elf = (struct elfhdr *)bufp; 985 1084 bufp += sizeof(struct elfhdr); 986 1085 987 1086 /* 988 - * setup ELF PT_NOTE, place holder for cpu notes info. The notes info 989 - * will be populated during second kernel boot after crash. Hence 990 - * this PT_NOTE will always be the first elf note. 1087 + * Set up ELF PT_NOTE, a placeholder for CPU notes information. 1088 + * The notes info will be populated later by platform-specific code. 1089 + * Hence, this PT_NOTE will always be the first ELF note. 991 1090 * 992 1091 * NOTE: Any new ELF note addition should be placed after this note. 993 1092 */ 994 1093 phdr = (struct elf_phdr *)bufp; 995 1094 bufp += sizeof(struct elf_phdr); 996 1095 phdr->p_type = PT_NOTE; 997 - phdr->p_flags = 0; 998 - phdr->p_vaddr = 0; 999 - phdr->p_align = 0; 1000 - 1001 - phdr->p_offset = 0; 1002 - phdr->p_paddr = 0; 1003 - phdr->p_filesz = 0; 1004 - phdr->p_memsz = 0; 1005 - 1096 + phdr->p_flags = 0; 1097 + phdr->p_vaddr = 0; 1098 + phdr->p_align = 0; 1099 + phdr->p_offset = 0; 1100 + phdr->p_paddr = 0; 1101 + phdr->p_filesz = 0; 1102 + phdr->p_memsz = 0; 1103 + /* Increment number of program headers. */ 1006 1104 (elf->e_phnum)++; 1007 1105 1008 1106 /* setup ELF PT_NOTE for vmcoreinfo */ ··· 1026 1096 phdr->p_flags = 0; 1027 1097 phdr->p_vaddr = 0; 1028 1098 phdr->p_align = 0; 1029 - 1030 - phdr->p_paddr = fadump_relocate(paddr_vmcoreinfo_note()); 1031 - phdr->p_offset = phdr->p_paddr; 1032 - phdr->p_memsz = phdr->p_filesz = VMCOREINFO_NOTE_SIZE; 1033 - 1099 + phdr->p_paddr = phdr->p_offset = fdh->vmcoreinfo_raddr; 1100 + phdr->p_memsz = phdr->p_filesz = fdh->vmcoreinfo_size; 1034 1101 /* Increment number of program headers. */ 1035 1102 (elf->e_phnum)++; 1036 1103 1037 - /* setup PT_LOAD sections. */ 1038 - j = 0; 1039 - offset = 0; 1040 - raddr = fw_dump.boot_mem_addr[0]; 1041 - for (i = 0; i < crash_mrange_info.mem_range_cnt; i++) { 1042 - u64 mbase, msize; 1043 - 1044 - mbase = crash_mrange_info.mem_ranges[i].base; 1045 - msize = crash_mrange_info.mem_ranges[i].size; 1046 - if (!msize) 1047 - continue; 1048 - 1104 + /* 1105 + * Setup PT_LOAD sections. first include boot memory regions 1106 + * and then add rest of the memory regions. 1107 + */ 1108 + boot_mem_dest_offset = fw_dump.boot_mem_dest_addr; 1109 + for (i = 0; i < fw_dump.boot_mem_regs_cnt; i++) { 1049 1110 phdr = (struct elf_phdr *)bufp; 1050 1111 bufp += sizeof(struct elf_phdr); 1051 - phdr->p_type = PT_LOAD; 1052 - phdr->p_flags = PF_R|PF_W|PF_X; 1053 - phdr->p_offset = mbase; 1112 + populate_elf_pt_load(phdr, fw_dump.boot_mem_addr[i], 1113 + fw_dump.boot_mem_sz[i], 1114 + boot_mem_dest_offset); 1115 + /* Increment number of program headers. */ 1116 + (elf->e_phnum)++; 1117 + boot_mem_dest_offset += fw_dump.boot_mem_sz[i]; 1118 + } 1054 1119 1055 - if (mbase == raddr) { 1056 - /* 1057 - * The entire real memory region will be moved by 1058 - * firmware to the specified destination_address. 1059 - * Hence set the correct offset. 1060 - */ 1061 - phdr->p_offset = fw_dump.boot_mem_dest_addr + offset; 1062 - if (j < (fw_dump.boot_mem_regs_cnt - 1)) { 1063 - offset += fw_dump.boot_mem_sz[j]; 1064 - raddr = fw_dump.boot_mem_addr[++j]; 1065 - } 1120 + /* Memory reserved for fadump in first kernel */ 1121 + ra_start = fw_dump.reserve_dump_area_start; 1122 + ra_size = get_fadump_area_size(); 1123 + ra_end = ra_start + ra_size; 1124 + 1125 + phdr = (struct elf_phdr *)bufp; 1126 + for_each_mem_range(i, &mstart, &mend) { 1127 + /* Boot memory regions already added, skip them now */ 1128 + if (mstart < fw_dump.boot_mem_top) { 1129 + if (mend > fw_dump.boot_mem_top) 1130 + mstart = fw_dump.boot_mem_top; 1131 + else 1132 + continue; 1066 1133 } 1067 1134 1068 - phdr->p_paddr = mbase; 1069 - phdr->p_vaddr = (unsigned long)__va(mbase); 1070 - phdr->p_filesz = msize; 1071 - phdr->p_memsz = msize; 1072 - phdr->p_align = 0; 1135 + /* Handle memblock regions overlaps with fadump reserved area */ 1136 + if ((ra_start < mend) && (ra_end > mstart)) { 1137 + if ((mstart < ra_start) && (mend > ra_end)) { 1138 + populate_elf_pt_load(phdr, mstart, ra_start - mstart, mstart); 1139 + /* Increment number of program headers. */ 1140 + (elf->e_phnum)++; 1141 + bufp += sizeof(struct elf_phdr); 1142 + phdr = (struct elf_phdr *)bufp; 1143 + populate_elf_pt_load(phdr, ra_end, mend - ra_end, ra_end); 1144 + } else if (mstart < ra_start) { 1145 + populate_elf_pt_load(phdr, mstart, ra_start - mstart, mstart); 1146 + } else if (ra_end < mend) { 1147 + populate_elf_pt_load(phdr, ra_end, mend - ra_end, ra_end); 1148 + } 1149 + } else { 1150 + /* No overlap with fadump reserved memory region */ 1151 + populate_elf_pt_load(phdr, mstart, mend - mstart, mstart); 1152 + } 1073 1153 1074 1154 /* Increment number of program headers. */ 1075 1155 (elf->e_phnum)++; 1156 + bufp += sizeof(struct elf_phdr); 1157 + phdr = (struct elf_phdr *) bufp; 1076 1158 } 1077 - return 0; 1078 1159 } 1079 1160 1080 1161 static unsigned long init_fadump_header(unsigned long addr) ··· 1100 1159 1101 1160 memset(fdh, 0, sizeof(struct fadump_crash_info_header)); 1102 1161 fdh->magic_number = FADUMP_CRASH_INFO_MAGIC; 1103 - fdh->elfcorehdr_addr = addr; 1162 + fdh->version = FADUMP_HEADER_VERSION; 1104 1163 /* We will set the crashing cpu id in crash_fadump() during crash. */ 1105 1164 fdh->crashing_cpu = FADUMP_CPU_UNKNOWN; 1165 + 1166 + /* 1167 + * The physical address and size of vmcoreinfo are required in the 1168 + * second kernel to prepare elfcorehdr. 1169 + */ 1170 + fdh->vmcoreinfo_raddr = fadump_relocate(paddr_vmcoreinfo_note()); 1171 + fdh->vmcoreinfo_size = VMCOREINFO_NOTE_SIZE; 1172 + 1173 + 1174 + fdh->pt_regs_sz = sizeof(struct pt_regs); 1106 1175 /* 1107 1176 * When LPAR is terminated by PYHP, ensure all possible CPUs' 1108 1177 * register data is processed while exporting the vmcore. 1109 1178 */ 1110 1179 fdh->cpu_mask = *cpu_possible_mask; 1180 + fdh->cpu_mask_sz = sizeof(struct cpumask); 1111 1181 1112 1182 return addr; 1113 1183 } ··· 1126 1174 static int register_fadump(void) 1127 1175 { 1128 1176 unsigned long addr; 1129 - void *vaddr; 1130 - int ret; 1131 1177 1132 1178 /* 1133 1179 * If no memory is reserved then we can not register for firmware- ··· 1134 1184 if (!fw_dump.reserve_dump_area_size) 1135 1185 return -ENODEV; 1136 1186 1137 - ret = fadump_setup_crash_memory_ranges(); 1138 - if (ret) 1139 - return ret; 1140 - 1141 1187 addr = fw_dump.fadumphdr_addr; 1142 1188 1143 1189 /* Initialize fadump crash info header. */ 1144 1190 addr = init_fadump_header(addr); 1145 - vaddr = __va(addr); 1146 - 1147 - pr_debug("Creating ELF core headers at %#016lx\n", addr); 1148 - fadump_create_elfcore_headers(vaddr); 1149 1191 1150 1192 /* register the future kernel dump with firmware. */ 1151 1193 pr_debug("Registering for firmware-assisted kernel dump...\n"); ··· 1156 1214 } else if (fw_dump.dump_registered) { 1157 1215 /* Un-register Firmware-assisted dump if it was registered. */ 1158 1216 fw_dump.ops->fadump_unregister(&fw_dump); 1159 - fadump_free_mem_ranges(&crash_mrange_info); 1160 1217 } 1161 1218 1162 1219 if (fw_dump.ops->fadump_cleanup) ··· 1341 1400 fadump_release_reserved_area(tstart, end); 1342 1401 } 1343 1402 1403 + static void fadump_free_elfcorehdr_buf(void) 1404 + { 1405 + if (fw_dump.elfcorehdr_addr == 0 || fw_dump.elfcorehdr_size == 0) 1406 + return; 1407 + 1408 + /* 1409 + * Before freeing the memory of `elfcorehdr`, reset the global 1410 + * `elfcorehdr_addr` to prevent modules like `vmcore` from accessing 1411 + * invalid memory. 1412 + */ 1413 + elfcorehdr_addr = ELFCORE_ADDR_ERR; 1414 + fadump_free_buffer(fw_dump.elfcorehdr_addr, fw_dump.elfcorehdr_size); 1415 + fw_dump.elfcorehdr_addr = 0; 1416 + fw_dump.elfcorehdr_size = 0; 1417 + } 1418 + 1344 1419 static void fadump_invalidate_release_mem(void) 1345 1420 { 1346 1421 mutex_lock(&fadump_mutex); ··· 1368 1411 fadump_cleanup(); 1369 1412 mutex_unlock(&fadump_mutex); 1370 1413 1414 + fadump_free_elfcorehdr_buf(); 1371 1415 fadump_release_memory(fw_dump.boot_mem_top, memblock_end_of_DRAM()); 1372 1416 fadump_free_cpu_notes_buf(); 1373 1417 ··· 1574 1616 return; 1575 1617 } 1576 1618 1619 + static int __init fadump_setup_elfcorehdr_buf(void) 1620 + { 1621 + int elf_phdr_cnt; 1622 + unsigned long elfcorehdr_size; 1623 + 1624 + /* 1625 + * Program header for CPU notes comes first, followed by one for 1626 + * vmcoreinfo, and the remaining program headers correspond to 1627 + * memory regions. 1628 + */ 1629 + elf_phdr_cnt = 2 + fw_dump.boot_mem_regs_cnt + memblock_num_regions(memory); 1630 + elfcorehdr_size = sizeof(struct elfhdr) + (elf_phdr_cnt * sizeof(struct elf_phdr)); 1631 + elfcorehdr_size = PAGE_ALIGN(elfcorehdr_size); 1632 + 1633 + fw_dump.elfcorehdr_addr = (u64)fadump_alloc_buffer(elfcorehdr_size); 1634 + if (!fw_dump.elfcorehdr_addr) { 1635 + pr_err("Failed to allocate %lu bytes for elfcorehdr\n", 1636 + elfcorehdr_size); 1637 + return -ENOMEM; 1638 + } 1639 + fw_dump.elfcorehdr_size = elfcorehdr_size; 1640 + return 0; 1641 + } 1642 + 1643 + /* 1644 + * Check if the fadump header of crashed kernel is compatible with fadump kernel. 1645 + * 1646 + * It checks the magic number, endianness, and size of non-primitive type 1647 + * members of fadump header to ensure safe dump collection. 1648 + */ 1649 + static bool __init is_fadump_header_compatible(struct fadump_crash_info_header *fdh) 1650 + { 1651 + if (fdh->magic_number == FADUMP_CRASH_INFO_MAGIC_OLD) { 1652 + pr_err("Old magic number, can't process the dump.\n"); 1653 + return false; 1654 + } 1655 + 1656 + if (fdh->magic_number != FADUMP_CRASH_INFO_MAGIC) { 1657 + if (fdh->magic_number == swab64(FADUMP_CRASH_INFO_MAGIC)) 1658 + pr_err("Endianness mismatch between the crashed and fadump kernels.\n"); 1659 + else 1660 + pr_err("Fadump header is corrupted.\n"); 1661 + 1662 + return false; 1663 + } 1664 + 1665 + /* 1666 + * Dump collection is not safe if the size of non-primitive type members 1667 + * of the fadump header do not match between crashed and fadump kernel. 1668 + */ 1669 + if (fdh->pt_regs_sz != sizeof(struct pt_regs) || 1670 + fdh->cpu_mask_sz != sizeof(struct cpumask)) { 1671 + pr_err("Fadump header size mismatch.\n"); 1672 + return false; 1673 + } 1674 + 1675 + return true; 1676 + } 1677 + 1678 + static void __init fadump_process(void) 1679 + { 1680 + struct fadump_crash_info_header *fdh; 1681 + 1682 + fdh = (struct fadump_crash_info_header *) __va(fw_dump.fadumphdr_addr); 1683 + if (!fdh) { 1684 + pr_err("Crash info header is empty.\n"); 1685 + goto err_out; 1686 + } 1687 + 1688 + /* Avoid processing the dump if fadump header isn't compatible */ 1689 + if (!is_fadump_header_compatible(fdh)) 1690 + goto err_out; 1691 + 1692 + /* Allocate buffer for elfcorehdr */ 1693 + if (fadump_setup_elfcorehdr_buf()) 1694 + goto err_out; 1695 + 1696 + fadump_populate_elfcorehdr(fdh); 1697 + 1698 + /* Let platform update the CPU notes in elfcorehdr */ 1699 + if (fw_dump.ops->fadump_process(&fw_dump) < 0) 1700 + goto err_out; 1701 + 1702 + /* 1703 + * elfcorehdr is now ready to be exported. 1704 + * 1705 + * set elfcorehdr_addr so that vmcore module will export the 1706 + * elfcorehdr through '/proc/vmcore'. 1707 + */ 1708 + elfcorehdr_addr = virt_to_phys((void *)fw_dump.elfcorehdr_addr); 1709 + return; 1710 + 1711 + err_out: 1712 + fadump_invalidate_release_mem(); 1713 + } 1714 + 1577 1715 /* 1578 1716 * Prepare for firmware-assisted dump. 1579 1717 */ ··· 1689 1635 * saving it to the disk. 1690 1636 */ 1691 1637 if (fw_dump.dump_active) { 1692 - /* 1693 - * if dump process fails then invalidate the registration 1694 - * and release memory before proceeding for re-registration. 1695 - */ 1696 - if (fw_dump.ops->fadump_process(&fw_dump) < 0) 1697 - fadump_invalidate_release_mem(); 1638 + fadump_process(); 1698 1639 } 1699 1640 /* Initialize the kernel dump memory structure and register with f/w */ 1700 1641 else if (fw_dump.reserve_dump_area_size) {
+3 -19
arch/powerpc/platforms/powernv/opal-fadump.c
··· 513 513 final_note(note_buf); 514 514 515 515 pr_debug("Updating elfcore header (%llx) with cpu notes\n", 516 - fdh->elfcorehdr_addr); 517 - fadump_update_elfcore_header(__va(fdh->elfcorehdr_addr)); 516 + fadump_conf->elfcorehdr_addr); 517 + fadump_update_elfcore_header((char *)fadump_conf->elfcorehdr_addr); 518 518 return 0; 519 519 } 520 520 ··· 526 526 if (!opal_fdm_active || !fadump_conf->fadumphdr_addr) 527 527 return rc; 528 528 529 - /* Validate the fadump crash info header */ 530 529 fdh = __va(fadump_conf->fadumphdr_addr); 531 - if (fdh->magic_number != FADUMP_CRASH_INFO_MAGIC) { 532 - pr_err("Crash info header is not valid.\n"); 533 - return rc; 534 - } 535 530 536 531 #ifdef CONFIG_OPAL_CORE 537 532 /* ··· 540 545 kernel_initiated = true; 541 546 #endif 542 547 543 - rc = opal_fadump_build_cpu_notes(fadump_conf, fdh); 544 - if (rc) 545 - return rc; 546 - 547 - /* 548 - * We are done validating dump info and elfcore header is now ready 549 - * to be exported. set elfcorehdr_addr so that vmcore module will 550 - * export the elfcore header through '/proc/vmcore'. 551 - */ 552 - elfcorehdr_addr = fdh->elfcorehdr_addr; 553 - 554 - return rc; 548 + return opal_fadump_build_cpu_notes(fadump_conf, fdh); 555 549 } 556 550 557 551 static void opal_fadump_region_show(struct fw_dump *fadump_conf,
+5 -29
arch/powerpc/platforms/pseries/rtas-fadump.c
··· 375 375 } 376 376 final_note(note_buf); 377 377 378 - if (fdh) { 379 - pr_debug("Updating elfcore header (%llx) with cpu notes\n", 380 - fdh->elfcorehdr_addr); 381 - fadump_update_elfcore_header(__va(fdh->elfcorehdr_addr)); 382 - } 378 + pr_debug("Updating elfcore header (%llx) with cpu notes\n", fadump_conf->elfcorehdr_addr); 379 + fadump_update_elfcore_header((char *)fadump_conf->elfcorehdr_addr); 383 380 return 0; 384 381 385 382 error_out: ··· 386 389 } 387 390 388 391 /* 389 - * Validate and process the dump data stored by firmware before exporting 390 - * it through '/proc/vmcore'. 392 + * Validate and process the dump data stored by the firmware, and update 393 + * the CPU notes of elfcorehdr. 391 394 */ 392 395 static int __init rtas_fadump_process(struct fw_dump *fadump_conf) 393 396 { 394 - struct fadump_crash_info_header *fdh; 395 - int rc = 0; 396 - 397 397 if (!fdm_active || !fadump_conf->fadumphdr_addr) 398 398 return -EINVAL; 399 399 ··· 409 415 return -EINVAL; 410 416 } 411 417 412 - /* Validate the fadump crash info header */ 413 - fdh = __va(fadump_conf->fadumphdr_addr); 414 - if (fdh->magic_number != FADUMP_CRASH_INFO_MAGIC) { 415 - pr_err("Crash info header is not valid.\n"); 416 - return -EINVAL; 417 - } 418 - 419 - rc = rtas_fadump_build_cpu_notes(fadump_conf); 420 - if (rc) 421 - return rc; 422 - 423 - /* 424 - * We are done validating dump info and elfcore header is now ready 425 - * to be exported. set elfcorehdr_addr so that vmcore module will 426 - * export the elfcore header through '/proc/vmcore'. 427 - */ 428 - elfcorehdr_addr = fdh->elfcorehdr_addr; 429 - 430 - return 0; 418 + return rtas_fadump_build_cpu_notes(fadump_conf); 431 419 } 432 420 433 421 static void rtas_fadump_region_show(struct fw_dump *fadump_conf,