3e776158b33065d6a30bf1bd781b7ad802160aef
[deliverable/linux.git] / arch / s390 / kernel / crash_dump.c
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 * Pointer to ELF header in new kernel
68 */
69 static void *elfcorehdr_newmem;
70
71 /*
72 * Copy one page from "oldmem"
73 *
74 * For the kdump reserved memory this functions performs a swap operation:
75 * - [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] is mapped to [0 - OLDMEM_SIZE].
76 * - [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
77 */
78 ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
79 size_t csize, unsigned long offset, int userbuf)
80 {
81 unsigned long src;
82 int rc;
83
84 if (!csize)
85 return 0;
86
87 src = (pfn << PAGE_SHIFT) + offset;
88 if (src < OLDMEM_SIZE)
89 src += OLDMEM_BASE;
90 else if (src > OLDMEM_BASE &&
91 src < OLDMEM_BASE + OLDMEM_SIZE)
92 src -= OLDMEM_BASE;
93 if (userbuf)
94 rc = copy_to_user_real((void __force __user *) buf,
95 (void *) src, csize);
96 else
97 rc = copy_page_real(buf, (void *) src, csize);
98 return (rc == 0) ? csize : rc;
99 }
100
101 /*
102 * Remap "oldmem"
103 *
104 * For the kdump reserved memory this functions performs a swap operation:
105 * [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
106 */
107 int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from,
108 unsigned long pfn, unsigned long size, pgprot_t prot)
109 {
110 unsigned long size_old;
111 int rc;
112
113 if (pfn < OLDMEM_SIZE >> PAGE_SHIFT) {
114 size_old = min(size, OLDMEM_SIZE - (pfn << PAGE_SHIFT));
115 rc = remap_pfn_range(vma, from,
116 pfn + (OLDMEM_BASE >> PAGE_SHIFT),
117 size_old, prot);
118 if (rc || size == size_old)
119 return rc;
120 size -= size_old;
121 from += size_old;
122 pfn += size_old >> PAGE_SHIFT;
123 }
124 return remap_pfn_range(vma, from, pfn, size, prot);
125 }
126
127 /*
128 * Copy memory from old kernel
129 */
130 int copy_from_oldmem(void *dest, void *src, size_t count)
131 {
132 unsigned long copied = 0;
133 int rc;
134
135 if ((unsigned long) src < OLDMEM_SIZE) {
136 copied = min(count, OLDMEM_SIZE - (unsigned long) src);
137 rc = memcpy_real(dest, src + OLDMEM_BASE, copied);
138 if (rc)
139 return rc;
140 }
141 return memcpy_real(dest + copied, src + copied, count - copied);
142 }
143
144 /*
145 * Alloc memory and panic in case of ENOMEM
146 */
147 static void *kzalloc_panic(int len)
148 {
149 void *rc;
150
151 rc = kzalloc(len, GFP_KERNEL);
152 if (!rc)
153 panic("s390 kdump kzalloc (%d) failed", len);
154 return rc;
155 }
156
157 /*
158 * Get memory layout and create hole for oldmem
159 */
160 static struct mem_chunk *get_memory_layout(void)
161 {
162 struct mem_chunk *chunk_array;
163
164 chunk_array = kzalloc_panic(MEMORY_CHUNKS * sizeof(struct mem_chunk));
165 detect_memory_layout(chunk_array, 0);
166 create_mem_hole(chunk_array, OLDMEM_BASE, OLDMEM_SIZE);
167 return chunk_array;
168 }
169
170 /*
171 * Initialize ELF note
172 */
173 static void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len,
174 const char *name)
175 {
176 Elf64_Nhdr *note;
177 u64 len;
178
179 note = (Elf64_Nhdr *)buf;
180 note->n_namesz = strlen(name) + 1;
181 note->n_descsz = d_len;
182 note->n_type = type;
183 len = sizeof(Elf64_Nhdr);
184
185 memcpy(buf + len, name, note->n_namesz);
186 len = roundup(len + note->n_namesz, 4);
187
188 memcpy(buf + len, desc, note->n_descsz);
189 len = roundup(len + note->n_descsz, 4);
190
191 return PTR_ADD(buf, len);
192 }
193
194 /*
195 * Initialize prstatus note
196 */
197 static void *nt_prstatus(void *ptr, struct save_area *sa)
198 {
199 struct elf_prstatus nt_prstatus;
200 static int cpu_nr = 1;
201
202 memset(&nt_prstatus, 0, sizeof(nt_prstatus));
203 memcpy(&nt_prstatus.pr_reg.gprs, sa->gp_regs, sizeof(sa->gp_regs));
204 memcpy(&nt_prstatus.pr_reg.psw, sa->psw, sizeof(sa->psw));
205 memcpy(&nt_prstatus.pr_reg.acrs, sa->acc_regs, sizeof(sa->acc_regs));
206 nt_prstatus.pr_pid = cpu_nr;
207 cpu_nr++;
208
209 return nt_init(ptr, NT_PRSTATUS, &nt_prstatus, sizeof(nt_prstatus),
210 "CORE");
211 }
212
213 /*
214 * Initialize fpregset (floating point) note
215 */
216 static void *nt_fpregset(void *ptr, struct save_area *sa)
217 {
218 elf_fpregset_t nt_fpregset;
219
220 memset(&nt_fpregset, 0, sizeof(nt_fpregset));
221 memcpy(&nt_fpregset.fpc, &sa->fp_ctrl_reg, sizeof(sa->fp_ctrl_reg));
222 memcpy(&nt_fpregset.fprs, &sa->fp_regs, sizeof(sa->fp_regs));
223
224 return nt_init(ptr, NT_PRFPREG, &nt_fpregset, sizeof(nt_fpregset),
225 "CORE");
226 }
227
228 /*
229 * Initialize timer note
230 */
231 static void *nt_s390_timer(void *ptr, struct save_area *sa)
232 {
233 return nt_init(ptr, NT_S390_TIMER, &sa->timer, sizeof(sa->timer),
234 KEXEC_CORE_NOTE_NAME);
235 }
236
237 /*
238 * Initialize TOD clock comparator note
239 */
240 static void *nt_s390_tod_cmp(void *ptr, struct save_area *sa)
241 {
242 return nt_init(ptr, NT_S390_TODCMP, &sa->clk_cmp,
243 sizeof(sa->clk_cmp), KEXEC_CORE_NOTE_NAME);
244 }
245
246 /*
247 * Initialize TOD programmable register note
248 */
249 static void *nt_s390_tod_preg(void *ptr, struct save_area *sa)
250 {
251 return nt_init(ptr, NT_S390_TODPREG, &sa->tod_reg,
252 sizeof(sa->tod_reg), KEXEC_CORE_NOTE_NAME);
253 }
254
255 /*
256 * Initialize control register note
257 */
258 static void *nt_s390_ctrs(void *ptr, struct save_area *sa)
259 {
260 return nt_init(ptr, NT_S390_CTRS, &sa->ctrl_regs,
261 sizeof(sa->ctrl_regs), KEXEC_CORE_NOTE_NAME);
262 }
263
264 /*
265 * Initialize prefix register note
266 */
267 static void *nt_s390_prefix(void *ptr, struct save_area *sa)
268 {
269 return nt_init(ptr, NT_S390_PREFIX, &sa->pref_reg,
270 sizeof(sa->pref_reg), KEXEC_CORE_NOTE_NAME);
271 }
272
273 /*
274 * Fill ELF notes for one CPU with save area registers
275 */
276 void *fill_cpu_elf_notes(void *ptr, struct save_area *sa)
277 {
278 ptr = nt_prstatus(ptr, sa);
279 ptr = nt_fpregset(ptr, sa);
280 ptr = nt_s390_timer(ptr, sa);
281 ptr = nt_s390_tod_cmp(ptr, sa);
282 ptr = nt_s390_tod_preg(ptr, sa);
283 ptr = nt_s390_ctrs(ptr, sa);
284 ptr = nt_s390_prefix(ptr, sa);
285 return ptr;
286 }
287
288 /*
289 * Initialize prpsinfo note (new kernel)
290 */
291 static void *nt_prpsinfo(void *ptr)
292 {
293 struct elf_prpsinfo prpsinfo;
294
295 memset(&prpsinfo, 0, sizeof(prpsinfo));
296 prpsinfo.pr_sname = 'R';
297 strcpy(prpsinfo.pr_fname, "vmlinux");
298 return nt_init(ptr, NT_PRPSINFO, &prpsinfo, sizeof(prpsinfo),
299 KEXEC_CORE_NOTE_NAME);
300 }
301
302 /*
303 * Get vmcoreinfo using lowcore->vmcore_info (new kernel)
304 */
305 static void *get_vmcoreinfo_old(unsigned long *size)
306 {
307 char nt_name[11], *vmcoreinfo;
308 Elf64_Nhdr note;
309 void *addr;
310
311 if (copy_from_oldmem(&addr, &S390_lowcore.vmcore_info, sizeof(addr)))
312 return NULL;
313 memset(nt_name, 0, sizeof(nt_name));
314 if (copy_from_oldmem(&note, addr, sizeof(note)))
315 return NULL;
316 if (copy_from_oldmem(nt_name, addr + sizeof(note), sizeof(nt_name) - 1))
317 return NULL;
318 if (strcmp(nt_name, "VMCOREINFO") != 0)
319 return NULL;
320 vmcoreinfo = kzalloc_panic(note.n_descsz);
321 if (copy_from_oldmem(vmcoreinfo, addr + 24, note.n_descsz))
322 return NULL;
323 *size = note.n_descsz;
324 return vmcoreinfo;
325 }
326
327 /*
328 * Initialize vmcoreinfo note (new kernel)
329 */
330 static void *nt_vmcoreinfo(void *ptr)
331 {
332 unsigned long size;
333 void *vmcoreinfo;
334
335 vmcoreinfo = os_info_old_entry(OS_INFO_VMCOREINFO, &size);
336 if (!vmcoreinfo)
337 vmcoreinfo = get_vmcoreinfo_old(&size);
338 if (!vmcoreinfo)
339 return ptr;
340 return nt_init(ptr, 0, vmcoreinfo, size, "VMCOREINFO");
341 }
342
343 /*
344 * Initialize ELF header (new kernel)
345 */
346 static void *ehdr_init(Elf64_Ehdr *ehdr, int mem_chunk_cnt)
347 {
348 memset(ehdr, 0, sizeof(*ehdr));
349 memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
350 ehdr->e_ident[EI_CLASS] = ELFCLASS64;
351 ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
352 ehdr->e_ident[EI_VERSION] = EV_CURRENT;
353 memset(ehdr->e_ident + EI_PAD, 0, EI_NIDENT - EI_PAD);
354 ehdr->e_type = ET_CORE;
355 ehdr->e_machine = EM_S390;
356 ehdr->e_version = EV_CURRENT;
357 ehdr->e_phoff = sizeof(Elf64_Ehdr);
358 ehdr->e_ehsize = sizeof(Elf64_Ehdr);
359 ehdr->e_phentsize = sizeof(Elf64_Phdr);
360 ehdr->e_phnum = mem_chunk_cnt + 1;
361 return ehdr + 1;
362 }
363
364 /*
365 * Return CPU count for ELF header (new kernel)
366 */
367 static int get_cpu_cnt(void)
368 {
369 int i, cpus = 0;
370
371 for (i = 0; zfcpdump_save_areas[i]; i++) {
372 if (zfcpdump_save_areas[i]->pref_reg == 0)
373 continue;
374 cpus++;
375 }
376 return cpus;
377 }
378
379 /*
380 * Return memory chunk count for ELF header (new kernel)
381 */
382 static int get_mem_chunk_cnt(void)
383 {
384 struct mem_chunk *chunk_array, *mem_chunk;
385 int i, cnt = 0;
386
387 chunk_array = get_memory_layout();
388 for (i = 0; i < MEMORY_CHUNKS; i++) {
389 mem_chunk = &chunk_array[i];
390 if (chunk_array[i].type != CHUNK_READ_WRITE &&
391 chunk_array[i].type != CHUNK_READ_ONLY)
392 continue;
393 if (mem_chunk->size == 0)
394 continue;
395 cnt++;
396 }
397 kfree(chunk_array);
398 return cnt;
399 }
400
401 /*
402 * Initialize ELF loads (new kernel)
403 */
404 static int loads_init(Elf64_Phdr *phdr, u64 loads_offset)
405 {
406 struct mem_chunk *chunk_array, *mem_chunk;
407 int i;
408
409 chunk_array = get_memory_layout();
410 for (i = 0; i < MEMORY_CHUNKS; i++) {
411 mem_chunk = &chunk_array[i];
412 if (mem_chunk->size == 0)
413 continue;
414 if (chunk_array[i].type != CHUNK_READ_WRITE &&
415 chunk_array[i].type != CHUNK_READ_ONLY)
416 continue;
417 else
418 phdr->p_filesz = mem_chunk->size;
419 phdr->p_type = PT_LOAD;
420 phdr->p_offset = mem_chunk->addr;
421 phdr->p_vaddr = mem_chunk->addr;
422 phdr->p_paddr = mem_chunk->addr;
423 phdr->p_memsz = mem_chunk->size;
424 phdr->p_flags = PF_R | PF_W | PF_X;
425 phdr->p_align = PAGE_SIZE;
426 phdr++;
427 }
428 kfree(chunk_array);
429 return i;
430 }
431
432 /*
433 * Initialize notes (new kernel)
434 */
435 static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
436 {
437 struct save_area *sa;
438 void *ptr_start = ptr;
439 int i;
440
441 ptr = nt_prpsinfo(ptr);
442
443 for (i = 0; zfcpdump_save_areas[i]; i++) {
444 sa = zfcpdump_save_areas[i];
445 if (sa->pref_reg == 0)
446 continue;
447 ptr = fill_cpu_elf_notes(ptr, sa);
448 }
449 ptr = nt_vmcoreinfo(ptr);
450 memset(phdr, 0, sizeof(*phdr));
451 phdr->p_type = PT_NOTE;
452 phdr->p_offset = notes_offset;
453 phdr->p_filesz = (unsigned long) PTR_SUB(ptr, ptr_start);
454 phdr->p_memsz = phdr->p_filesz;
455 return ptr;
456 }
457
458 /*
459 * Create ELF core header (new kernel)
460 */
461 int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
462 {
463 Elf64_Phdr *phdr_notes, *phdr_loads;
464 int mem_chunk_cnt;
465 void *ptr, *hdr;
466 u32 alloc_size;
467 u64 hdr_off;
468
469 if (!OLDMEM_BASE)
470 return 0;
471 /* If elfcorehdr= has been passed via cmdline, we use that one */
472 if (elfcorehdr_addr != ELFCORE_ADDR_MAX)
473 return 0;
474 mem_chunk_cnt = get_mem_chunk_cnt();
475
476 alloc_size = 0x1000 + get_cpu_cnt() * 0x300 +
477 mem_chunk_cnt * sizeof(Elf64_Phdr);
478 hdr = kzalloc_panic(alloc_size);
479 /* Init elf header */
480 ptr = ehdr_init(hdr, mem_chunk_cnt);
481 /* Init program headers */
482 phdr_notes = ptr;
483 ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr));
484 phdr_loads = ptr;
485 ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr) * mem_chunk_cnt);
486 /* Init notes */
487 hdr_off = PTR_DIFF(ptr, hdr);
488 ptr = notes_init(phdr_notes, ptr, ((unsigned long) hdr) + hdr_off);
489 /* Init loads */
490 hdr_off = PTR_DIFF(ptr, hdr);
491 loads_init(phdr_loads, hdr_off);
492 *addr = (unsigned long long) hdr;
493 elfcorehdr_newmem = hdr;
494 *size = (unsigned long long) hdr_off;
495 BUG_ON(elfcorehdr_size > alloc_size);
496 return 0;
497 }
498
499 /*
500 * Free ELF core header (new kernel)
501 */
502 void elfcorehdr_free(unsigned long long addr)
503 {
504 if (!elfcorehdr_newmem)
505 return;
506 kfree((void *)(unsigned long)addr);
507 }
508
509 /*
510 * Read from ELF header
511 */
512 ssize_t elfcorehdr_read(char *buf, size_t count, u64 *ppos)
513 {
514 void *src = (void *)(unsigned long)*ppos;
515
516 src = elfcorehdr_newmem ? src : src - OLDMEM_BASE;
517 memcpy(buf, src, count);
518 *ppos += count;
519 return count;
520 }
521
522 /*
523 * Read from ELF notes data
524 */
525 ssize_t elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos)
526 {
527 void *src = (void *)(unsigned long)*ppos;
528 int rc;
529
530 if (elfcorehdr_newmem) {
531 memcpy(buf, src, count);
532 } else {
533 rc = copy_from_oldmem(buf, src, count);
534 if (rc)
535 return rc;
536 }
537 *ppos += count;
538 return count;
539 }
This page took 0.05192 seconds and 4 git commands to generate.