1 /* 2 * S390 kdump implementation 3 * 4 * Copyright IBM Corp. 2011 5 * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> 6 */ 7 8 #include <linux/crash_dump.h> 9 #include <asm/lowcore.h> 10 #include <linux/kernel.h> 11 #include <linux/module.h> 12 #include <linux/gfp.h> 13 #include <linux/slab.h> 14 #include <linux/bootmem.h> 15 #include <linux/elf.h> 16 #include <asm/os_info.h> 17 #include <asm/elf.h> 18 #include <asm/ipl.h> 19 20 #define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y))) 21 #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y))) 22 #define PTR_DIFF(x, y) ((unsigned long)(((char *) (x)) - ((unsigned long) (y)))) 23 24 25 /* 26 * Return physical address for virtual address 27 */ 28 static inline void *load_real_addr(void *addr) 29 { 30 unsigned long real_addr; 31 32 asm volatile( 33 " lra %0,0(%1)\n" 34 " jz 0f\n" 35 " la %0,0\n" 36 "0:" 37 : "=a" (real_addr) : "a" (addr) : "cc"); 38 return (void *)real_addr; 39 } 40 41 /* 42 * Copy up to one page to vmalloc or real memory 43 */ 44 static ssize_t copy_page_real(void *buf, void *src, size_t csize) 45 { 46 size_t size; 47 48 if (is_vmalloc_addr(buf)) { 49 BUG_ON(csize >= PAGE_SIZE); 50 /* If buf is not page aligned, copy first part */ 51 size = min(roundup(__pa(buf), PAGE_SIZE) - __pa(buf), csize); 52 if (size) { 53 if (memcpy_real(load_real_addr(buf), src, size)) 54 return -EFAULT; 55 buf += size; 56 src += size; 57 } 58 /* Copy second part */ 59 size = csize - size; 60 return (size) ? memcpy_real(load_real_addr(buf), src, size) : 0; 61 } else { 62 return memcpy_real(buf, src, csize); 63 } 64 } 65 66 /* 67 * Copy one page from "oldmem" 68 * 69 * For the kdump reserved memory this functions performs a swap operation: 70 * - [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] is mapped to [0 - OLDMEM_SIZE]. 71 * - [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] 72 */ 73 ssize_t copy_oldmem_page(unsigned long pfn, char *buf, 74 size_t csize, unsigned long offset, int userbuf) 75 { 76 unsigned long src; 77 int rc; 78 79 if (!csize) 80 return 0; 81 82 src = (pfn << PAGE_SHIFT) + offset; 83 if (src < OLDMEM_SIZE) 84 src += OLDMEM_BASE; 85 else if (src > OLDMEM_BASE && 86 src < OLDMEM_BASE + OLDMEM_SIZE) 87 src -= OLDMEM_BASE; 88 if (userbuf) 89 rc = copy_to_user_real((void __force __user *) buf, 90 (void *) src, csize); 91 else 92 rc = copy_page_real(buf, (void *) src, csize); 93 return (rc == 0) ? csize : rc; 94 } 95 96 /* 97 * Copy memory from old kernel 98 */ 99 int copy_from_oldmem(void *dest, void *src, size_t count) 100 { 101 unsigned long copied = 0; 102 int rc; 103 104 if ((unsigned long) src < OLDMEM_SIZE) { 105 copied = min(count, OLDMEM_SIZE - (unsigned long) src); 106 rc = memcpy_real(dest, src + OLDMEM_BASE, copied); 107 if (rc) 108 return rc; 109 } 110 return memcpy_real(dest + copied, src + copied, count - copied); 111 } 112 113 /* 114 * Alloc memory and panic in case of ENOMEM 115 */ 116 static void *kzalloc_panic(int len) 117 { 118 void *rc; 119 120 rc = kzalloc(len, GFP_KERNEL); 121 if (!rc) 122 panic("s390 kdump kzalloc (%d) failed", len); 123 return rc; 124 } 125 126 /* 127 * Get memory layout and create hole for oldmem 128 */ 129 static struct mem_chunk *get_memory_layout(void) 130 { 131 struct mem_chunk *chunk_array; 132 133 chunk_array = kzalloc_panic(MEMORY_CHUNKS * sizeof(struct mem_chunk)); 134 detect_memory_layout(chunk_array, 0); 135 create_mem_hole(chunk_array, OLDMEM_BASE, OLDMEM_SIZE); 136 return chunk_array; 137 } 138 139 /* 140 * Initialize ELF note 141 */ 142 static void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len, 143 const char *name) 144 { 145 Elf64_Nhdr *note; 146 u64 len; 147 148 note = (Elf64_Nhdr *)buf; 149 note->n_namesz = strlen(name) + 1; 150 note->n_descsz = d_len; 151 note->n_type = type; 152 len = sizeof(Elf64_Nhdr); 153 154 memcpy(buf + len, name, note->n_namesz); 155 len = roundup(len + note->n_namesz, 4); 156 157 memcpy(buf + len, desc, note->n_descsz); 158 len = roundup(len + note->n_descsz, 4); 159 160 return PTR_ADD(buf, len); 161 } 162 163 /* 164 * Initialize prstatus note 165 */ 166 static void *nt_prstatus(void *ptr, struct save_area *sa) 167 { 168 struct elf_prstatus nt_prstatus; 169 static int cpu_nr = 1; 170 171 memset(&nt_prstatus, 0, sizeof(nt_prstatus)); 172 memcpy(&nt_prstatus.pr_reg.gprs, sa->gp_regs, sizeof(sa->gp_regs)); 173 memcpy(&nt_prstatus.pr_reg.psw, sa->psw, sizeof(sa->psw)); 174 memcpy(&nt_prstatus.pr_reg.acrs, sa->acc_regs, sizeof(sa->acc_regs)); 175 nt_prstatus.pr_pid = cpu_nr; 176 cpu_nr++; 177 178 return nt_init(ptr, NT_PRSTATUS, &nt_prstatus, sizeof(nt_prstatus), 179 "CORE"); 180 } 181 182 /* 183 * Initialize fpregset (floating point) note 184 */ 185 static void *nt_fpregset(void *ptr, struct save_area *sa) 186 { 187 elf_fpregset_t nt_fpregset; 188 189 memset(&nt_fpregset, 0, sizeof(nt_fpregset)); 190 memcpy(&nt_fpregset.fpc, &sa->fp_ctrl_reg, sizeof(sa->fp_ctrl_reg)); 191 memcpy(&nt_fpregset.fprs, &sa->fp_regs, sizeof(sa->fp_regs)); 192 193 return nt_init(ptr, NT_PRFPREG, &nt_fpregset, sizeof(nt_fpregset), 194 "CORE"); 195 } 196 197 /* 198 * Initialize timer note 199 */ 200 static void *nt_s390_timer(void *ptr, struct save_area *sa) 201 { 202 return nt_init(ptr, NT_S390_TIMER, &sa->timer, sizeof(sa->timer), 203 KEXEC_CORE_NOTE_NAME); 204 } 205 206 /* 207 * Initialize TOD clock comparator note 208 */ 209 static void *nt_s390_tod_cmp(void *ptr, struct save_area *sa) 210 { 211 return nt_init(ptr, NT_S390_TODCMP, &sa->clk_cmp, 212 sizeof(sa->clk_cmp), KEXEC_CORE_NOTE_NAME); 213 } 214 215 /* 216 * Initialize TOD programmable register note 217 */ 218 static void *nt_s390_tod_preg(void *ptr, struct save_area *sa) 219 { 220 return nt_init(ptr, NT_S390_TODPREG, &sa->tod_reg, 221 sizeof(sa->tod_reg), KEXEC_CORE_NOTE_NAME); 222 } 223 224 /* 225 * Initialize control register note 226 */ 227 static void *nt_s390_ctrs(void *ptr, struct save_area *sa) 228 { 229 return nt_init(ptr, NT_S390_CTRS, &sa->ctrl_regs, 230 sizeof(sa->ctrl_regs), KEXEC_CORE_NOTE_NAME); 231 } 232 233 /* 234 * Initialize prefix register note 235 */ 236 static void *nt_s390_prefix(void *ptr, struct save_area *sa) 237 { 238 return nt_init(ptr, NT_S390_PREFIX, &sa->pref_reg, 239 sizeof(sa->pref_reg), KEXEC_CORE_NOTE_NAME); 240 } 241 242 /* 243 * Fill ELF notes for one CPU with save area registers 244 */ 245 void *fill_cpu_elf_notes(void *ptr, struct save_area *sa) 246 { 247 ptr = nt_prstatus(ptr, sa); 248 ptr = nt_fpregset(ptr, sa); 249 ptr = nt_s390_timer(ptr, sa); 250 ptr = nt_s390_tod_cmp(ptr, sa); 251 ptr = nt_s390_tod_preg(ptr, sa); 252 ptr = nt_s390_ctrs(ptr, sa); 253 ptr = nt_s390_prefix(ptr, sa); 254 return ptr; 255 } 256 257 /* 258 * Initialize prpsinfo note (new kernel) 259 */ 260 static void *nt_prpsinfo(void *ptr) 261 { 262 struct elf_prpsinfo prpsinfo; 263 264 memset(&prpsinfo, 0, sizeof(prpsinfo)); 265 prpsinfo.pr_sname = 'R'; 266 strcpy(prpsinfo.pr_fname, "vmlinux"); 267 return nt_init(ptr, NT_PRPSINFO, &prpsinfo, sizeof(prpsinfo), 268 KEXEC_CORE_NOTE_NAME); 269 } 270 271 /* 272 * Get vmcoreinfo using lowcore->vmcore_info (new kernel) 273 */ 274 static void *get_vmcoreinfo_old(unsigned long *size) 275 { 276 char nt_name[11], *vmcoreinfo; 277 Elf64_Nhdr note; 278 void *addr; 279 280 if (copy_from_oldmem(&addr, &S390_lowcore.vmcore_info, sizeof(addr))) 281 return NULL; 282 memset(nt_name, 0, sizeof(nt_name)); 283 if (copy_from_oldmem(¬e, addr, sizeof(note))) 284 return NULL; 285 if (copy_from_oldmem(nt_name, addr + sizeof(note), sizeof(nt_name) - 1)) 286 return NULL; 287 if (strcmp(nt_name, "VMCOREINFO") != 0) 288 return NULL; 289 vmcoreinfo = kzalloc_panic(note.n_descsz); 290 if (copy_from_oldmem(vmcoreinfo, addr + 24, note.n_descsz)) 291 return NULL; 292 *size = note.n_descsz; 293 return vmcoreinfo; 294 } 295 296 /* 297 * Initialize vmcoreinfo note (new kernel) 298 */ 299 static void *nt_vmcoreinfo(void *ptr) 300 { 301 unsigned long size; 302 void *vmcoreinfo; 303 304 vmcoreinfo = os_info_old_entry(OS_INFO_VMCOREINFO, &size); 305 if (!vmcoreinfo) 306 vmcoreinfo = get_vmcoreinfo_old(&size); 307 if (!vmcoreinfo) 308 return ptr; 309 return nt_init(ptr, 0, vmcoreinfo, size, "VMCOREINFO"); 310 } 311 312 /* 313 * Initialize ELF header (new kernel) 314 */ 315 static void *ehdr_init(Elf64_Ehdr *ehdr, int mem_chunk_cnt) 316 { 317 memset(ehdr, 0, sizeof(*ehdr)); 318 memcpy(ehdr->e_ident, ELFMAG, SELFMAG); 319 ehdr->e_ident[EI_CLASS] = ELFCLASS64; 320 ehdr->e_ident[EI_DATA] = ELFDATA2MSB; 321 ehdr->e_ident[EI_VERSION] = EV_CURRENT; 322 memset(ehdr->e_ident + EI_PAD, 0, EI_NIDENT - EI_PAD); 323 ehdr->e_type = ET_CORE; 324 ehdr->e_machine = EM_S390; 325 ehdr->e_version = EV_CURRENT; 326 ehdr->e_phoff = sizeof(Elf64_Ehdr); 327 ehdr->e_ehsize = sizeof(Elf64_Ehdr); 328 ehdr->e_phentsize = sizeof(Elf64_Phdr); 329 ehdr->e_phnum = mem_chunk_cnt + 1; 330 return ehdr + 1; 331 } 332 333 /* 334 * Return CPU count for ELF header (new kernel) 335 */ 336 static int get_cpu_cnt(void) 337 { 338 int i, cpus = 0; 339 340 for (i = 0; zfcpdump_save_areas[i]; i++) { 341 if (zfcpdump_save_areas[i]->pref_reg == 0) 342 continue; 343 cpus++; 344 } 345 return cpus; 346 } 347 348 /* 349 * Return memory chunk count for ELF header (new kernel) 350 */ 351 static int get_mem_chunk_cnt(void) 352 { 353 struct mem_chunk *chunk_array, *mem_chunk; 354 int i, cnt = 0; 355 356 chunk_array = get_memory_layout(); 357 for (i = 0; i < MEMORY_CHUNKS; i++) { 358 mem_chunk = &chunk_array[i]; 359 if (chunk_array[i].type != CHUNK_READ_WRITE && 360 chunk_array[i].type != CHUNK_READ_ONLY) 361 continue; 362 if (mem_chunk->size == 0) 363 continue; 364 cnt++; 365 } 366 kfree(chunk_array); 367 return cnt; 368 } 369 370 /* 371 * Relocate pointer in order to allow vmcore code access the data 372 */ 373 static inline unsigned long relocate(unsigned long addr) 374 { 375 return OLDMEM_BASE + addr; 376 } 377 378 /* 379 * Initialize ELF loads (new kernel) 380 */ 381 static int loads_init(Elf64_Phdr *phdr, u64 loads_offset) 382 { 383 struct mem_chunk *chunk_array, *mem_chunk; 384 int i; 385 386 chunk_array = get_memory_layout(); 387 for (i = 0; i < MEMORY_CHUNKS; i++) { 388 mem_chunk = &chunk_array[i]; 389 if (mem_chunk->size == 0) 390 continue; 391 if (chunk_array[i].type != CHUNK_READ_WRITE && 392 chunk_array[i].type != CHUNK_READ_ONLY) 393 continue; 394 else 395 phdr->p_filesz = mem_chunk->size; 396 phdr->p_type = PT_LOAD; 397 phdr->p_offset = mem_chunk->addr; 398 phdr->p_vaddr = mem_chunk->addr; 399 phdr->p_paddr = mem_chunk->addr; 400 phdr->p_memsz = mem_chunk->size; 401 phdr->p_flags = PF_R | PF_W | PF_X; 402 phdr->p_align = PAGE_SIZE; 403 phdr++; 404 } 405 kfree(chunk_array); 406 return i; 407 } 408 409 /* 410 * Initialize notes (new kernel) 411 */ 412 static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset) 413 { 414 struct save_area *sa; 415 void *ptr_start = ptr; 416 int i; 417 418 ptr = nt_prpsinfo(ptr); 419 420 for (i = 0; zfcpdump_save_areas[i]; i++) { 421 sa = zfcpdump_save_areas[i]; 422 if (sa->pref_reg == 0) 423 continue; 424 ptr = fill_cpu_elf_notes(ptr, sa); 425 } 426 ptr = nt_vmcoreinfo(ptr); 427 memset(phdr, 0, sizeof(*phdr)); 428 phdr->p_type = PT_NOTE; 429 phdr->p_offset = relocate(notes_offset); 430 phdr->p_filesz = (unsigned long) PTR_SUB(ptr, ptr_start); 431 phdr->p_memsz = phdr->p_filesz; 432 return ptr; 433 } 434 435 /* 436 * Create ELF core header (new kernel) 437 */ 438 static void s390_elf_corehdr_create(char **elfcorebuf, size_t *elfcorebuf_sz) 439 { 440 Elf64_Phdr *phdr_notes, *phdr_loads; 441 int mem_chunk_cnt; 442 void *ptr, *hdr; 443 u32 alloc_size; 444 u64 hdr_off; 445 446 mem_chunk_cnt = get_mem_chunk_cnt(); 447 448 alloc_size = 0x1000 + get_cpu_cnt() * 0x300 + 449 mem_chunk_cnt * sizeof(Elf64_Phdr); 450 hdr = kzalloc_panic(alloc_size); 451 /* Init elf header */ 452 ptr = ehdr_init(hdr, mem_chunk_cnt); 453 /* Init program headers */ 454 phdr_notes = ptr; 455 ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr)); 456 phdr_loads = ptr; 457 ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr) * mem_chunk_cnt); 458 /* Init notes */ 459 hdr_off = PTR_DIFF(ptr, hdr); 460 ptr = notes_init(phdr_notes, ptr, ((unsigned long) hdr) + hdr_off); 461 /* Init loads */ 462 hdr_off = PTR_DIFF(ptr, hdr); 463 loads_init(phdr_loads, ((unsigned long) hdr) + hdr_off); 464 *elfcorebuf_sz = hdr_off; 465 *elfcorebuf = (void *) relocate((unsigned long) hdr); 466 BUG_ON(*elfcorebuf_sz > alloc_size); 467 } 468 469 /* 470 * Create kdump ELF core header in new kernel, if it has not been passed via 471 * the "elfcorehdr" kernel parameter 472 */ 473 static int setup_kdump_elfcorehdr(void) 474 { 475 size_t elfcorebuf_sz; 476 char *elfcorebuf; 477 478 if (!OLDMEM_BASE || is_kdump_kernel()) 479 return -EINVAL; 480 s390_elf_corehdr_create(&elfcorebuf, &elfcorebuf_sz); 481 elfcorehdr_addr = (unsigned long long) elfcorebuf; 482 elfcorehdr_size = elfcorebuf_sz; 483 return 0; 484 } 485 486 subsys_initcall(setup_kdump_elfcorehdr); 487