diff options
-rw-r--r-- | arch/s390/Kconfig | 3 | ||||
-rw-r--r-- | arch/s390/include/asm/sclp.h | 1 | ||||
-rw-r--r-- | arch/s390/kernel/crash_dump.c | 122 | ||||
-rw-r--r-- | drivers/s390/char/zcore.c | 6 |
4 files changed, 110 insertions, 22 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index fb2723e8ba65..3ec272859e1e 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -526,6 +526,7 @@ config CRASH_DUMP | |||
526 | bool "kernel crash dumps" | 526 | bool "kernel crash dumps" |
527 | depends on 64BIT && SMP | 527 | depends on 64BIT && SMP |
528 | select KEXEC | 528 | select KEXEC |
529 | select ZFCPDUMP | ||
529 | help | 530 | help |
530 | Generate crash dump after being started by kexec. | 531 | Generate crash dump after being started by kexec. |
531 | Crash dump kernels are loaded in the main kernel with kexec-tools | 532 | Crash dump kernels are loaded in the main kernel with kexec-tools |
@@ -536,7 +537,7 @@ config CRASH_DUMP | |||
536 | config ZFCPDUMP | 537 | config ZFCPDUMP |
537 | def_bool n | 538 | def_bool n |
538 | prompt "zfcpdump support" | 539 | prompt "zfcpdump support" |
539 | select SMP | 540 | depends on SMP |
540 | help | 541 | help |
541 | Select this option if you want to build an zfcpdump enabled kernel. | 542 | Select this option if you want to build an zfcpdump enabled kernel. |
542 | Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this. | 543 | Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this. |
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index 06a136136047..7dc7f9c63b65 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h | |||
@@ -56,5 +56,6 @@ bool sclp_has_linemode(void); | |||
56 | bool sclp_has_vt220(void); | 56 | bool sclp_has_vt220(void); |
57 | int sclp_pci_configure(u32 fid); | 57 | int sclp_pci_configure(u32 fid); |
58 | int sclp_pci_deconfigure(u32 fid); | 58 | int sclp_pci_deconfigure(u32 fid); |
59 | int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode); | ||
59 | 60 | ||
60 | #endif /* _ASM_S390_SCLP_H */ | 61 | #endif /* _ASM_S390_SCLP_H */ |
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index 3e776158b330..c84f33d51f7b 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <asm/os_info.h> | 16 | #include <asm/os_info.h> |
17 | #include <asm/elf.h> | 17 | #include <asm/elf.h> |
18 | #include <asm/ipl.h> | 18 | #include <asm/ipl.h> |
19 | #include <asm/sclp.h> | ||
19 | 20 | ||
20 | #define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y))) | 21 | #define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y))) |
21 | #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y))) | 22 | #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y))) |
@@ -69,22 +70,41 @@ static ssize_t copy_page_real(void *buf, void *src, size_t csize) | |||
69 | static void *elfcorehdr_newmem; | 70 | static void *elfcorehdr_newmem; |
70 | 71 | ||
71 | /* | 72 | /* |
72 | * Copy one page from "oldmem" | 73 | * Copy one page from zfcpdump "oldmem" |
74 | * | ||
75 | * For pages below ZFCPDUMP_HSA_SIZE memory from the HSA is copied. Otherwise | ||
76 | * real memory copy is used. | ||
77 | */ | ||
78 | static ssize_t copy_oldmem_page_zfcpdump(char *buf, size_t csize, | ||
79 | unsigned long src, int userbuf) | ||
80 | { | ||
81 | int rc; | ||
82 | |||
83 | if (src < ZFCPDUMP_HSA_SIZE) { | ||
84 | rc = memcpy_hsa(buf, src, csize, userbuf); | ||
85 | } else { | ||
86 | if (userbuf) | ||
87 | rc = copy_to_user_real((void __force __user *) buf, | ||
88 | (void *) src, csize); | ||
89 | else | ||
90 | rc = memcpy_real(buf, (void *) src, csize); | ||
91 | } | ||
92 | return rc ? rc : csize; | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * Copy one page from kdump "oldmem" | ||
73 | * | 97 | * |
74 | * For the kdump reserved memory this functions performs a swap operation: | 98 | * For the kdump reserved memory this functions performs a swap operation: |
75 | * - [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] is mapped to [0 - OLDMEM_SIZE]. | 99 | * - [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] | 100 | * - [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] |
77 | */ | 101 | */ |
78 | ssize_t copy_oldmem_page(unsigned long pfn, char *buf, | 102 | static ssize_t copy_oldmem_page_kdump(char *buf, size_t csize, |
79 | size_t csize, unsigned long offset, int userbuf) | 103 | unsigned long src, int userbuf) |
104 | |||
80 | { | 105 | { |
81 | unsigned long src; | ||
82 | int rc; | 106 | int rc; |
83 | 107 | ||
84 | if (!csize) | ||
85 | return 0; | ||
86 | |||
87 | src = (pfn << PAGE_SHIFT) + offset; | ||
88 | if (src < OLDMEM_SIZE) | 108 | if (src < OLDMEM_SIZE) |
89 | src += OLDMEM_BASE; | 109 | src += OLDMEM_BASE; |
90 | else if (src > OLDMEM_BASE && | 110 | else if (src > OLDMEM_BASE && |
@@ -95,17 +115,35 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, | |||
95 | (void *) src, csize); | 115 | (void *) src, csize); |
96 | else | 116 | else |
97 | rc = copy_page_real(buf, (void *) src, csize); | 117 | rc = copy_page_real(buf, (void *) src, csize); |
98 | return (rc == 0) ? csize : rc; | 118 | return (rc == 0) ? rc : csize; |
99 | } | 119 | } |
100 | 120 | ||
101 | /* | 121 | /* |
102 | * Remap "oldmem" | 122 | * Copy one page from "oldmem" |
123 | */ | ||
124 | ssize_t copy_oldmem_page(unsigned long pfn, char *buf, size_t csize, | ||
125 | unsigned long offset, int userbuf) | ||
126 | { | ||
127 | unsigned long src; | ||
128 | |||
129 | if (!csize) | ||
130 | return 0; | ||
131 | src = (pfn << PAGE_SHIFT) + offset; | ||
132 | if (OLDMEM_BASE) | ||
133 | return copy_oldmem_page_kdump(buf, csize, src, userbuf); | ||
134 | else | ||
135 | return copy_oldmem_page_zfcpdump(buf, csize, src, userbuf); | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * Remap "oldmem" for kdump | ||
103 | * | 140 | * |
104 | * For the kdump reserved memory this functions performs a swap operation: | 141 | * For the kdump reserved memory this functions performs a swap operation: |
105 | * [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] | 142 | * [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] |
106 | */ | 143 | */ |
107 | int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from, | 144 | static int remap_oldmem_pfn_range_kdump(struct vm_area_struct *vma, |
108 | unsigned long pfn, unsigned long size, pgprot_t prot) | 145 | unsigned long from, unsigned long pfn, |
146 | unsigned long size, pgprot_t prot) | ||
109 | { | 147 | { |
110 | unsigned long size_old; | 148 | unsigned long size_old; |
111 | int rc; | 149 | int rc; |
@@ -125,6 +163,43 @@ int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from, | |||
125 | } | 163 | } |
126 | 164 | ||
127 | /* | 165 | /* |
166 | * Remap "oldmem" for zfcpdump | ||
167 | * | ||
168 | * We only map available memory above ZFCPDUMP_HSA_SIZE. Memory below | ||
169 | * ZFCPDUMP_HSA_SIZE is read on demand using the copy_oldmem_page() function. | ||
170 | */ | ||
171 | static int remap_oldmem_pfn_range_zfcpdump(struct vm_area_struct *vma, | ||
172 | unsigned long from, | ||
173 | unsigned long pfn, | ||
174 | unsigned long size, pgprot_t prot) | ||
175 | { | ||
176 | unsigned long size_hsa; | ||
177 | |||
178 | if (pfn < ZFCPDUMP_HSA_SIZE >> PAGE_SHIFT) { | ||
179 | size_hsa = min(size, ZFCPDUMP_HSA_SIZE - (pfn << PAGE_SHIFT)); | ||
180 | if (size == size_hsa) | ||
181 | return 0; | ||
182 | size -= size_hsa; | ||
183 | from += size_hsa; | ||
184 | pfn += size_hsa >> PAGE_SHIFT; | ||
185 | } | ||
186 | return remap_pfn_range(vma, from, pfn, size, prot); | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * Remap "oldmem" for kdump or zfcpdump | ||
191 | */ | ||
192 | int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from, | ||
193 | unsigned long pfn, unsigned long size, pgprot_t prot) | ||
194 | { | ||
195 | if (OLDMEM_BASE) | ||
196 | return remap_oldmem_pfn_range_kdump(vma, from, pfn, size, prot); | ||
197 | else | ||
198 | return remap_oldmem_pfn_range_zfcpdump(vma, from, pfn, size, | ||
199 | prot); | ||
200 | } | ||
201 | |||
202 | /* | ||
128 | * Copy memory from old kernel | 203 | * Copy memory from old kernel |
129 | */ | 204 | */ |
130 | int copy_from_oldmem(void *dest, void *src, size_t count) | 205 | int copy_from_oldmem(void *dest, void *src, size_t count) |
@@ -132,11 +207,21 @@ int copy_from_oldmem(void *dest, void *src, size_t count) | |||
132 | unsigned long copied = 0; | 207 | unsigned long copied = 0; |
133 | int rc; | 208 | int rc; |
134 | 209 | ||
135 | if ((unsigned long) src < OLDMEM_SIZE) { | 210 | if (OLDMEM_BASE) { |
136 | copied = min(count, OLDMEM_SIZE - (unsigned long) src); | 211 | if ((unsigned long) src < OLDMEM_SIZE) { |
137 | rc = memcpy_real(dest, src + OLDMEM_BASE, copied); | 212 | copied = min(count, OLDMEM_SIZE - (unsigned long) src); |
138 | if (rc) | 213 | rc = memcpy_real(dest, src + OLDMEM_BASE, copied); |
139 | return rc; | 214 | if (rc) |
215 | return rc; | ||
216 | } | ||
217 | } else { | ||
218 | if ((unsigned long) src < ZFCPDUMP_HSA_SIZE) { | ||
219 | copied = min(count, | ||
220 | ZFCPDUMP_HSA_SIZE - (unsigned long) src); | ||
221 | rc = memcpy_hsa(dest, (unsigned long) src, copied, 0); | ||
222 | if (rc) | ||
223 | return rc; | ||
224 | } | ||
140 | } | 225 | } |
141 | return memcpy_real(dest + copied, src + copied, count - copied); | 226 | return memcpy_real(dest + copied, src + copied, count - copied); |
142 | } | 227 | } |
@@ -466,7 +551,8 @@ int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size) | |||
466 | u32 alloc_size; | 551 | u32 alloc_size; |
467 | u64 hdr_off; | 552 | u64 hdr_off; |
468 | 553 | ||
469 | if (!OLDMEM_BASE) | 554 | /* If we are not in kdump or zfcpdump mode return */ |
555 | if (!OLDMEM_BASE && ipl_info.type != IPL_TYPE_FCP_DUMP) | ||
470 | return 0; | 556 | return 0; |
471 | /* If elfcorehdr= has been passed via cmdline, we use that one */ | 557 | /* If elfcorehdr= has been passed via cmdline, we use that one */ |
472 | if (elfcorehdr_addr != ELFCORE_ADDR_MAX) | 558 | if (elfcorehdr_addr != ELFCORE_ADDR_MAX) |
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 9e5e14686e75..794820a123d0 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c | |||
@@ -30,8 +30,8 @@ | |||
30 | 30 | ||
31 | #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x) | 31 | #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x) |
32 | 32 | ||
33 | #define TO_USER 0 | 33 | #define TO_USER 1 |
34 | #define TO_KERNEL 1 | 34 | #define TO_KERNEL 0 |
35 | #define CHUNK_INFO_SIZE 34 /* 2 16-byte char, each followed by blank */ | 35 | #define CHUNK_INFO_SIZE 34 /* 2 16-byte char, each followed by blank */ |
36 | 36 | ||
37 | enum arch_id { | 37 | enum arch_id { |
@@ -73,7 +73,7 @@ static struct ipl_parameter_block *ipl_block; | |||
73 | * @count: Size of buffer, which should be copied | 73 | * @count: Size of buffer, which should be copied |
74 | * @mode: Either TO_KERNEL or TO_USER | 74 | * @mode: Either TO_KERNEL or TO_USER |
75 | */ | 75 | */ |
76 | static int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode) | 76 | int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode) |
77 | { | 77 | { |
78 | int offs, blk_num; | 78 | int offs, blk_num; |
79 | static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); | 79 | static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); |