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

s390/zcore: copy vector registers into the image data

The /sys/kernel/debug/zcore/mem interface delivers the memory of the
old system with the CPU registers stored to the assigned locations in
each prefix page.

For the vector registers the prefix page of each CPU has an address of
a 1024 byte save area at 0x11b0. But the /sys/kernel/debug/zcore/mem
interface fails copy the vector registers saved at boot of the zfcpdump
kernel into the dump image.

Copy the saved vector registers of a CPU to the outout buffer if the
memory area that is read via /sys/kernel/debug/zcore/mem intersects
with the vector register save area of this CPU.

Acked-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

+55 -16
+1
arch/s390/include/asm/lowcore.h
··· 35 35 struct save_area_ext { 36 36 struct save_area sa; 37 37 __vector128 vx_regs[32]; 38 + u64 vx_sa_addr; 38 39 }; 39 40 40 41 struct _lowcore {
+54 -16
drivers/s390/char/zcore.c
··· 28 28 #include <asm/processor.h> 29 29 #include <asm/irqflags.h> 30 30 #include <asm/checksum.h> 31 + #include <asm/os_info.h> 31 32 #include <asm/switch_to.h> 32 33 #include "sclp.h" 33 34 ··· 152 151 static int __init init_cpu_info(enum arch_id arch) 153 152 { 154 153 struct save_area_ext *sa_ext; 154 + struct _lowcore *lc; 155 + void *ptr; 156 + int i; 155 157 156 158 /* get info for boot cpu from lowcore, stored in the HSA */ 157 159 ··· 166 162 TRACE("could not copy from HSA\n"); 167 163 return -EIO; 168 164 } 169 - if (MACHINE_HAS_VX) 170 - save_vx_regs_safe(sa_ext->vx_regs); 165 + if (!MACHINE_HAS_VX) 166 + return 0; 167 + 168 + save_vx_regs_safe(sa_ext->vx_regs); 169 + /* Get address of the vector register save area for each CPU */ 170 + for (i = 0; i < dump_save_areas.count; i++) { 171 + sa_ext = dump_save_areas.areas[i]; 172 + lc = (struct _lowcore *)(unsigned long) sa_ext->sa.pref_reg; 173 + ptr = &lc->vector_save_area_addr; 174 + copy_from_oldmem(&sa_ext->vx_sa_addr, ptr, 175 + sizeof(sa_ext->vx_sa_addr)); 176 + } 171 177 return 0; 172 178 } 173 179 ··· 259 245 */ 260 246 static int zcore_add_lc(char __user *buf, unsigned long start, size_t count) 261 247 { 248 + struct save_area_ext *sa_ext; 249 + struct save_area *sa; 262 250 unsigned long end; 263 251 int i; 264 252 ··· 271 255 for (i = 0; i < dump_save_areas.count; i++) { 272 256 unsigned long cp_start, cp_end; /* copy range */ 273 257 unsigned long sa_start, sa_end; /* save area range */ 274 - unsigned long prefix; 275 258 unsigned long sa_off, len, buf_off; 276 - struct save_area *save_area = &dump_save_areas.areas[i]->sa; 277 259 278 - prefix = save_area->pref_reg; 279 - sa_start = prefix + sys_info.sa_base; 280 - sa_end = prefix + sys_info.sa_base + sys_info.sa_size; 260 + sa_ext = dump_save_areas.areas[i]; 261 + sa = &sa_ext->sa; 281 262 282 - if ((end < sa_start) || (start > sa_end)) 263 + /* Copy the 512 bytes lowcore save area 0x1200 - 0x1400 */ 264 + sa_start = sa->pref_reg + sys_info.sa_base; 265 + sa_end = sa_start + sys_info.sa_size; 266 + 267 + if (end >= sa_start && start < sa_end) { 268 + cp_start = max(start, sa_start); 269 + cp_end = min(end, sa_end); 270 + buf_off = cp_start - start; 271 + sa_off = cp_start - sa_start; 272 + len = cp_end - cp_start; 273 + 274 + TRACE("copy_lc: %lx-%lx\n", cp_start, cp_end); 275 + if (copy_lc(buf + buf_off, sa, sa_off, len)) 276 + return -EFAULT; 277 + } 278 + 279 + if (!MACHINE_HAS_VX) 283 280 continue; 284 - cp_start = max(start, sa_start); 285 - cp_end = min(end, sa_end); 286 281 287 - buf_off = cp_start - start; 288 - sa_off = cp_start - sa_start; 289 - len = cp_end - cp_start; 282 + /* Copy the 512 bytes vector save area */ 283 + sa_start = sa_ext->vx_sa_addr & -1024UL; 284 + sa_end = sa_start + 512; 290 285 291 - TRACE("copy_lc for: %lx\n", start); 292 - if (copy_lc(buf + buf_off, save_area, sa_off, len)) 293 - return -EFAULT; 286 + if (end >= sa_start && start < sa_end) { 287 + cp_start = max(start, sa_start); 288 + cp_end = min(end, sa_end); 289 + 290 + buf_off = cp_start - start; 291 + sa_off = cp_start - sa_start; 292 + len = cp_end - cp_start; 293 + 294 + TRACE("copy vxrs: %lx-%lx\n", cp_start, cp_end); 295 + if (copy_to_user(buf + buf_off, 296 + (void *) &sa_ext->vx_regs + sa_off, 297 + len)) 298 + return -EFAULT; 299 + } 294 300 } 295 301 return 0; 296 302 }