diff options
Diffstat (limited to 'arch/s390/kernel/crash_dump.c')
-rw-r--r-- | arch/s390/kernel/crash_dump.c | 75 |
1 files changed, 49 insertions, 26 deletions
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index c84f33d51f7b..f45b2ab0cb81 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c | |||
@@ -22,6 +22,32 @@ | |||
22 | #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y))) | 22 | #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y))) |
23 | #define PTR_DIFF(x, y) ((unsigned long)(((char *) (x)) - ((unsigned long) (y)))) | 23 | #define PTR_DIFF(x, y) ((unsigned long)(((char *) (x)) - ((unsigned long) (y)))) |
24 | 24 | ||
25 | struct dump_save_areas dump_save_areas; | ||
26 | |||
27 | /* | ||
28 | * Allocate and add a save area for a CPU | ||
29 | */ | ||
30 | struct save_area *dump_save_area_create(int cpu) | ||
31 | { | ||
32 | struct save_area **save_areas, *save_area; | ||
33 | |||
34 | save_area = kmalloc(sizeof(*save_area), GFP_KERNEL); | ||
35 | if (!save_area) | ||
36 | return NULL; | ||
37 | if (cpu + 1 > dump_save_areas.count) { | ||
38 | dump_save_areas.count = cpu + 1; | ||
39 | save_areas = krealloc(dump_save_areas.areas, | ||
40 | dump_save_areas.count * sizeof(void *), | ||
41 | GFP_KERNEL | __GFP_ZERO); | ||
42 | if (!save_areas) { | ||
43 | kfree(save_area); | ||
44 | return NULL; | ||
45 | } | ||
46 | dump_save_areas.areas = save_areas; | ||
47 | } | ||
48 | dump_save_areas.areas[cpu] = save_area; | ||
49 | return save_area; | ||
50 | } | ||
25 | 51 | ||
26 | /* | 52 | /* |
27 | * Return physical address for virtual address | 53 | * Return physical address for virtual address |
@@ -40,28 +66,25 @@ static inline void *load_real_addr(void *addr) | |||
40 | } | 66 | } |
41 | 67 | ||
42 | /* | 68 | /* |
43 | * Copy up to one page to vmalloc or real memory | 69 | * Copy real to virtual or real memory |
44 | */ | 70 | */ |
45 | static ssize_t copy_page_real(void *buf, void *src, size_t csize) | 71 | static int copy_from_realmem(void *dest, void *src, size_t count) |
46 | { | 72 | { |
47 | size_t size; | 73 | unsigned long size; |
48 | 74 | ||
49 | if (is_vmalloc_addr(buf)) { | 75 | if (!count) |
50 | BUG_ON(csize >= PAGE_SIZE); | 76 | return 0; |
51 | /* If buf is not page aligned, copy first part */ | 77 | if (!is_vmalloc_or_module_addr(dest)) |
52 | size = min(roundup(__pa(buf), PAGE_SIZE) - __pa(buf), csize); | 78 | return memcpy_real(dest, src, count); |
53 | if (size) { | 79 | do { |
54 | if (memcpy_real(load_real_addr(buf), src, size)) | 80 | size = min(count, PAGE_SIZE - (__pa(dest) & ~PAGE_MASK)); |
55 | return -EFAULT; | 81 | if (memcpy_real(load_real_addr(dest), src, size)) |
56 | buf += size; | 82 | return -EFAULT; |
57 | src += size; | 83 | count -= size; |
58 | } | 84 | dest += size; |
59 | /* Copy second part */ | 85 | src += size; |
60 | size = csize - size; | 86 | } while (count); |
61 | return (size) ? memcpy_real(load_real_addr(buf), src, size) : 0; | 87 | return 0; |
62 | } else { | ||
63 | return memcpy_real(buf, src, csize); | ||
64 | } | ||
65 | } | 88 | } |
66 | 89 | ||
67 | /* | 90 | /* |
@@ -114,7 +137,7 @@ static ssize_t copy_oldmem_page_kdump(char *buf, size_t csize, | |||
114 | rc = copy_to_user_real((void __force __user *) buf, | 137 | rc = copy_to_user_real((void __force __user *) buf, |
115 | (void *) src, csize); | 138 | (void *) src, csize); |
116 | else | 139 | else |
117 | rc = copy_page_real(buf, (void *) src, csize); | 140 | rc = copy_from_realmem(buf, (void *) src, csize); |
118 | return (rc == 0) ? rc : csize; | 141 | return (rc == 0) ? rc : csize; |
119 | } | 142 | } |
120 | 143 | ||
@@ -210,7 +233,7 @@ int copy_from_oldmem(void *dest, void *src, size_t count) | |||
210 | if (OLDMEM_BASE) { | 233 | if (OLDMEM_BASE) { |
211 | if ((unsigned long) src < OLDMEM_SIZE) { | 234 | if ((unsigned long) src < OLDMEM_SIZE) { |
212 | copied = min(count, OLDMEM_SIZE - (unsigned long) src); | 235 | copied = min(count, OLDMEM_SIZE - (unsigned long) src); |
213 | rc = memcpy_real(dest, src + OLDMEM_BASE, copied); | 236 | rc = copy_from_realmem(dest, src + OLDMEM_BASE, copied); |
214 | if (rc) | 237 | if (rc) |
215 | return rc; | 238 | return rc; |
216 | } | 239 | } |
@@ -223,7 +246,7 @@ int copy_from_oldmem(void *dest, void *src, size_t count) | |||
223 | return rc; | 246 | return rc; |
224 | } | 247 | } |
225 | } | 248 | } |
226 | return memcpy_real(dest + copied, src + copied, count - copied); | 249 | return copy_from_realmem(dest + copied, src + copied, count - copied); |
227 | } | 250 | } |
228 | 251 | ||
229 | /* | 252 | /* |
@@ -453,8 +476,8 @@ static int get_cpu_cnt(void) | |||
453 | { | 476 | { |
454 | int i, cpus = 0; | 477 | int i, cpus = 0; |
455 | 478 | ||
456 | for (i = 0; zfcpdump_save_areas[i]; i++) { | 479 | for (i = 0; i < dump_save_areas.count; i++) { |
457 | if (zfcpdump_save_areas[i]->pref_reg == 0) | 480 | if (dump_save_areas.areas[i]->pref_reg == 0) |
458 | continue; | 481 | continue; |
459 | cpus++; | 482 | cpus++; |
460 | } | 483 | } |
@@ -525,8 +548,8 @@ static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset) | |||
525 | 548 | ||
526 | ptr = nt_prpsinfo(ptr); | 549 | ptr = nt_prpsinfo(ptr); |
527 | 550 | ||
528 | for (i = 0; zfcpdump_save_areas[i]; i++) { | 551 | for (i = 0; i < dump_save_areas.count; i++) { |
529 | sa = zfcpdump_save_areas[i]; | 552 | sa = dump_save_areas.areas[i]; |
530 | if (sa->pref_reg == 0) | 553 | if (sa->pref_reg == 0) |
531 | continue; | 554 | continue; |
532 | ptr = fill_cpu_elf_notes(ptr, sa); | 555 | ptr = fill_cpu_elf_notes(ptr, sa); |