xref: /openbmc/linux/drivers/s390/char/zcore.c (revision 36c0f8b3)
1 /*
2  * zcore module to export memory content and register sets for creating system
3  * dumps on SCSI disks (zfcpdump). The "zcore/mem" debugfs file shows the same
4  * dump format as s390 standalone dumps.
5  *
6  * For more information please refer to Documentation/s390/zfcpdump.txt
7  *
8  * Copyright IBM Corp. 2003, 2008
9  * Author(s): Michael Holzheu
10  */
11 
12 #define KMSG_COMPONENT "zdump"
13 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
14 
15 #include <linux/init.h>
16 #include <linux/slab.h>
17 #include <linux/miscdevice.h>
18 #include <linux/debugfs.h>
19 #include <linux/module.h>
20 #include <linux/memblock.h>
21 
22 #include <asm/asm-offsets.h>
23 #include <asm/ipl.h>
24 #include <asm/sclp.h>
25 #include <asm/setup.h>
26 #include <asm/uaccess.h>
27 #include <asm/debug.h>
28 #include <asm/processor.h>
29 #include <asm/irqflags.h>
30 #include <asm/checksum.h>
31 #include <asm/os_info.h>
32 #include <asm/switch_to.h>
33 #include "sclp.h"
34 
35 #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x)
36 
37 #define CHUNK_INFO_SIZE	34 /* 2 16-byte char, each followed by blank */
38 
39 enum arch_id {
40 	ARCH_S390	= 0,
41 	ARCH_S390X	= 1,
42 };
43 
44 struct ipib_info {
45 	unsigned long	ipib;
46 	u32		checksum;
47 }  __attribute__((packed));
48 
49 static struct debug_info *zcore_dbf;
50 static int hsa_available;
51 static struct dentry *zcore_dir;
52 static struct dentry *zcore_memmap_file;
53 static struct dentry *zcore_reipl_file;
54 static struct dentry *zcore_hsa_file;
55 static struct ipl_parameter_block *ipl_block;
56 
57 static char hsa_buf[PAGE_SIZE] __aligned(PAGE_SIZE);
58 
59 /*
60  * Copy memory from HSA to user memory (not reentrant):
61  *
62  * @dest:  User buffer where memory should be copied to
63  * @src:   Start address within HSA where data should be copied
64  * @count: Size of buffer, which should be copied
65  */
66 int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count)
67 {
68 	unsigned long offset, bytes;
69 
70 	if (!hsa_available)
71 		return -ENODATA;
72 
73 	while (count) {
74 		if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) {
75 			TRACE("sclp_sdias_copy() failed\n");
76 			return -EIO;
77 		}
78 		offset = src % PAGE_SIZE;
79 		bytes = min(PAGE_SIZE - offset, count);
80 		if (copy_to_user(dest, hsa_buf + offset, bytes))
81 			return -EFAULT;
82 		src += bytes;
83 		dest += bytes;
84 		count -= bytes;
85 	}
86 	return 0;
87 }
88 
89 /*
90  * Copy memory from HSA to kernel memory (not reentrant):
91  *
92  * @dest:  Kernel or user buffer where memory should be copied to
93  * @src:   Start address within HSA where data should be copied
94  * @count: Size of buffer, which should be copied
95  */
96 int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
97 {
98 	unsigned long offset, bytes;
99 
100 	if (!hsa_available)
101 		return -ENODATA;
102 
103 	while (count) {
104 		if (sclp_sdias_copy(hsa_buf, src / PAGE_SIZE + 2, 1)) {
105 			TRACE("sclp_sdias_copy() failed\n");
106 			return -EIO;
107 		}
108 		offset = src % PAGE_SIZE;
109 		bytes = min(PAGE_SIZE - offset, count);
110 		memcpy(dest, hsa_buf + offset, bytes);
111 		src += bytes;
112 		dest += bytes;
113 		count -= bytes;
114 	}
115 	return 0;
116 }
117 
118 static int __init init_cpu_info(void)
119 {
120 	struct save_area *sa;
121 
122 	/* get info for boot cpu from lowcore, stored in the HSA */
123 	sa = save_area_boot_cpu();
124 	if (!sa)
125 		return -ENOMEM;
126 	if (memcpy_hsa_kernel(hsa_buf, __LC_FPREGS_SAVE_AREA, 512) < 0) {
127 		TRACE("could not copy from HSA\n");
128 		return -EIO;
129 	}
130 	save_area_add_regs(sa, hsa_buf); /* vx registers are saved in smp.c */
131 	return 0;
132 }
133 
134 /*
135  * Release the HSA
136  */
137 static void release_hsa(void)
138 {
139 	diag308(DIAG308_REL_HSA, NULL);
140 	hsa_available = 0;
141 }
142 
143 static ssize_t zcore_memmap_read(struct file *filp, char __user *buf,
144 				 size_t count, loff_t *ppos)
145 {
146 	return simple_read_from_buffer(buf, count, ppos, filp->private_data,
147 				       memblock.memory.cnt * CHUNK_INFO_SIZE);
148 }
149 
150 static int zcore_memmap_open(struct inode *inode, struct file *filp)
151 {
152 	struct memblock_region *reg;
153 	char *buf;
154 	int i = 0;
155 
156 	buf = kzalloc(memblock.memory.cnt * CHUNK_INFO_SIZE, GFP_KERNEL);
157 	if (!buf) {
158 		return -ENOMEM;
159 	}
160 	for_each_memblock(memory, reg) {
161 		sprintf(buf + (i++ * CHUNK_INFO_SIZE), "%016llx %016llx ",
162 			(unsigned long long) reg->base,
163 			(unsigned long long) reg->size);
164 	}
165 	filp->private_data = buf;
166 	return nonseekable_open(inode, filp);
167 }
168 
169 static int zcore_memmap_release(struct inode *inode, struct file *filp)
170 {
171 	kfree(filp->private_data);
172 	return 0;
173 }
174 
175 static const struct file_operations zcore_memmap_fops = {
176 	.owner		= THIS_MODULE,
177 	.read		= zcore_memmap_read,
178 	.open		= zcore_memmap_open,
179 	.release	= zcore_memmap_release,
180 	.llseek		= no_llseek,
181 };
182 
183 static ssize_t zcore_reipl_write(struct file *filp, const char __user *buf,
184 				 size_t count, loff_t *ppos)
185 {
186 	if (ipl_block) {
187 		diag308(DIAG308_SET, ipl_block);
188 		diag308(DIAG308_IPL, NULL);
189 	}
190 	return count;
191 }
192 
193 static int zcore_reipl_open(struct inode *inode, struct file *filp)
194 {
195 	return nonseekable_open(inode, filp);
196 }
197 
198 static int zcore_reipl_release(struct inode *inode, struct file *filp)
199 {
200 	return 0;
201 }
202 
203 static const struct file_operations zcore_reipl_fops = {
204 	.owner		= THIS_MODULE,
205 	.write		= zcore_reipl_write,
206 	.open		= zcore_reipl_open,
207 	.release	= zcore_reipl_release,
208 	.llseek		= no_llseek,
209 };
210 
211 static ssize_t zcore_hsa_read(struct file *filp, char __user *buf,
212 			      size_t count, loff_t *ppos)
213 {
214 	static char str[18];
215 
216 	if (hsa_available)
217 		snprintf(str, sizeof(str), "%lx\n", sclp.hsa_size);
218 	else
219 		snprintf(str, sizeof(str), "0\n");
220 	return simple_read_from_buffer(buf, count, ppos, str, strlen(str));
221 }
222 
223 static ssize_t zcore_hsa_write(struct file *filp, const char __user *buf,
224 			       size_t count, loff_t *ppos)
225 {
226 	char value;
227 
228 	if (*ppos != 0)
229 		return -EPIPE;
230 	if (copy_from_user(&value, buf, 1))
231 		return -EFAULT;
232 	if (value != '0')
233 		return -EINVAL;
234 	release_hsa();
235 	return count;
236 }
237 
238 static const struct file_operations zcore_hsa_fops = {
239 	.owner		= THIS_MODULE,
240 	.write		= zcore_hsa_write,
241 	.read		= zcore_hsa_read,
242 	.open		= nonseekable_open,
243 	.llseek		= no_llseek,
244 };
245 
246 static int __init check_sdias(void)
247 {
248 	if (!sclp.hsa_size) {
249 		TRACE("Could not determine HSA size\n");
250 		return -ENODEV;
251 	}
252 	return 0;
253 }
254 
255 /*
256  * Provide IPL parameter information block from either HSA or memory
257  * for future reipl
258  */
259 static int __init zcore_reipl_init(void)
260 {
261 	struct ipib_info ipib_info;
262 	int rc;
263 
264 	rc = memcpy_hsa_kernel(&ipib_info, __LC_DUMP_REIPL, sizeof(ipib_info));
265 	if (rc)
266 		return rc;
267 	if (ipib_info.ipib == 0)
268 		return 0;
269 	ipl_block = (void *) __get_free_page(GFP_KERNEL);
270 	if (!ipl_block)
271 		return -ENOMEM;
272 	if (ipib_info.ipib < sclp.hsa_size)
273 		rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE);
274 	else
275 		rc = memcpy_real(ipl_block, (void *) ipib_info.ipib, PAGE_SIZE);
276 	if (rc || csum_partial(ipl_block, ipl_block->hdr.len, 0) !=
277 	    ipib_info.checksum) {
278 		TRACE("Checksum does not match\n");
279 		free_page((unsigned long) ipl_block);
280 		ipl_block = NULL;
281 	}
282 	return 0;
283 }
284 
285 static int __init zcore_init(void)
286 {
287 	unsigned char arch;
288 	int rc;
289 
290 	if (ipl_info.type != IPL_TYPE_FCP_DUMP)
291 		return -ENODATA;
292 	if (OLDMEM_BASE)
293 		return -ENODATA;
294 
295 	zcore_dbf = debug_register("zcore", 4, 1, 4 * sizeof(long));
296 	debug_register_view(zcore_dbf, &debug_sprintf_view);
297 	debug_set_level(zcore_dbf, 6);
298 
299 	TRACE("devno:  %x\n", ipl_info.data.fcp.dev_id.devno);
300 	TRACE("wwpn:   %llx\n", (unsigned long long) ipl_info.data.fcp.wwpn);
301 	TRACE("lun:    %llx\n", (unsigned long long) ipl_info.data.fcp.lun);
302 
303 	rc = sclp_sdias_init();
304 	if (rc)
305 		goto fail;
306 
307 	rc = check_sdias();
308 	if (rc)
309 		goto fail;
310 	hsa_available = 1;
311 
312 	rc = memcpy_hsa_kernel(&arch, __LC_AR_MODE_ID, 1);
313 	if (rc)
314 		goto fail;
315 
316 	if (arch == ARCH_S390) {
317 		pr_alert("The 64-bit dump tool cannot be used for a "
318 			 "32-bit system\n");
319 		rc = -EINVAL;
320 		goto fail;
321 	}
322 
323 	pr_alert("DETECTED 'S390X (64 bit) OS'\n");
324 	rc = init_cpu_info();
325 	if (rc)
326 		goto fail;
327 
328 	rc = zcore_reipl_init();
329 	if (rc)
330 		goto fail;
331 
332 	zcore_dir = debugfs_create_dir("zcore" , NULL);
333 	if (!zcore_dir) {
334 		rc = -ENOMEM;
335 		goto fail;
336 	}
337 	zcore_memmap_file = debugfs_create_file("memmap", S_IRUSR, zcore_dir,
338 						NULL, &zcore_memmap_fops);
339 	if (!zcore_memmap_file) {
340 		rc = -ENOMEM;
341 		goto fail_dir;
342 	}
343 	zcore_reipl_file = debugfs_create_file("reipl", S_IRUSR, zcore_dir,
344 						NULL, &zcore_reipl_fops);
345 	if (!zcore_reipl_file) {
346 		rc = -ENOMEM;
347 		goto fail_memmap_file;
348 	}
349 	zcore_hsa_file = debugfs_create_file("hsa", S_IRUSR|S_IWUSR, zcore_dir,
350 					     NULL, &zcore_hsa_fops);
351 	if (!zcore_hsa_file) {
352 		rc = -ENOMEM;
353 		goto fail_reipl_file;
354 	}
355 	return 0;
356 
357 fail_reipl_file:
358 	debugfs_remove(zcore_reipl_file);
359 fail_memmap_file:
360 	debugfs_remove(zcore_memmap_file);
361 fail_dir:
362 	debugfs_remove(zcore_dir);
363 fail:
364 	diag308(DIAG308_REL_HSA, NULL);
365 	return rc;
366 }
367 
368 static void __exit zcore_exit(void)
369 {
370 	debug_unregister(zcore_dbf);
371 	sclp_sdias_exit();
372 	free_page((unsigned long) ipl_block);
373 	debugfs_remove(zcore_hsa_file);
374 	debugfs_remove(zcore_reipl_file);
375 	debugfs_remove(zcore_memmap_file);
376 	debugfs_remove(zcore_dir);
377 	diag308(DIAG308_REL_HSA, NULL);
378 }
379 
380 MODULE_AUTHOR("Copyright IBM Corp. 2003,2008");
381 MODULE_DESCRIPTION("zcore module for zfcpdump support");
382 MODULE_LICENSE("GPL");
383 
384 subsys_initcall(zcore_init);
385 module_exit(zcore_exit);
386