File Index
Files and directories
Sign in
FILE

papr-platform-dump.c

File preview with syntax highlighting.

linux-6.19.14/arch/powerpc/platforms/pseries/papr-platform-dump.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2
  3#define pr_fmt(fmt) "papr-platform-dump: " fmt
  4
  5#include <linux/anon_inodes.h>
  6#include <linux/file.h>
  7#include <linux/fs.h>
  8#include <linux/init.h>
  9#include <linux/kernel.h>
 10#include <linux/miscdevice.h>
 11#include <asm/machdep.h>
 12#include <asm/rtas-work-area.h>
 13#include <asm/rtas.h>
 14#include <uapi/asm/papr-platform-dump.h>
 15
 16/*
 17 * Function-specific return values for ibm,platform-dump, derived from
 18 * PAPR+ v2.13 7.3.3.4.1 "ibm,platform-dump RTAS Call".
 19 */
 20#define	RTAS_IBM_PLATFORM_DUMP_COMPLETE	0	/* Complete dump retrieved. */
 21#define	RTAS_IBM_PLATFORM_DUMP_CONTINUE	1	/* Continue dump */
 22#define	RTAS_NOT_AUTHORIZED		-9002	/* Not Authorized */
 23
 24#define	RTAS_IBM_PLATFORM_DUMP_START	2 /* Linux status to start dump */
 25
 26/**
 27 * struct ibm_platform_dump_params - Parameters (in and out) for
 28 *                                              ibm,platform-dump
 29 * @work_area:		In: work area buffer for results.
 30 * @buf_length:		In: work area buffer length in bytes
 31 * @dump_tag_hi:	In: Most-significant 32 bits of a Dump_Tag representing
 32 *                      an id of the dump being processed.
 33 * @dump_tag_lo:	In: Least-significant 32 bits of a Dump_Tag representing
 34 *                      an id of the dump being processed.
 35 * @sequence_hi:	In: Sequence number in most-significant 32 bits.
 36 *                      Out: Next sequence number in most-significant 32 bits.
 37 * @sequence_lo:	In: Sequence number in Least-significant 32 bits
 38 *                      Out: Next sequence number in Least-significant 32 bits.
 39 * @bytes_ret_hi:	Out: Bytes written in most-significant 32 bits.
 40 * @bytes_ret_lo:	Out: Bytes written in Least-significant 32 bits.
 41 * @status:		Out: RTAS call status.
 42 * @list:		Maintain the list of dumps are in progress. Can
 43 *                      retrieve multiple dumps with different dump IDs at
 44 *                      the same time but not with the same dump ID. This list
 45 *                      is used to determine whether the dump for the same ID
 46 *                      is in progress.
 47 */
 48struct ibm_platform_dump_params {
 49	struct rtas_work_area	*work_area;
 50	u32			buf_length;
 51	u32			dump_tag_hi;
 52	u32			dump_tag_lo;
 53	u32			sequence_hi;
 54	u32			sequence_lo;
 55	u32			bytes_ret_hi;
 56	u32			bytes_ret_lo;
 57	s32			status;
 58	struct list_head	list;
 59};
 60
 61/*
 62 * Multiple dumps with different dump IDs can be retrieved at the same
 63 * time, but not with dame dump ID. platform_dump_list_mutex and
 64 * platform_dump_list are used to prevent this behavior.
 65 */
 66static DEFINE_MUTEX(platform_dump_list_mutex);
 67static LIST_HEAD(platform_dump_list);
 68
 69/**
 70 * rtas_ibm_platform_dump() - Call ibm,platform-dump to fill a work area
 71 * buffer.
 72 * @params: See &struct ibm_platform_dump_params.
 73 * @buf_addr: Address of dump buffer (work_area)
 74 * @buf_length: Length of the buffer in bytes (min. 1024)
 75 *
 76 * Calls ibm,platform-dump until it errors or successfully deposits data
 77 * into the supplied work area. Handles RTAS retry statuses. Maps RTAS
 78 * error statuses to reasonable errno values.
 79 *
 80 * Can request multiple dumps with different dump IDs at the same time,
 81 * but not with the same dump ID which is prevented with the check in
 82 * the ioctl code (papr_platform_dump_create_handle()).
 83 *
 84 * The caller should inspect @params.status to determine whether more
 85 * calls are needed to complete the sequence.
 86 *
 87 * Context: May sleep.
 88 * Return: -ve on error, 0 for dump complete and 1 for continue dump
 89 */
 90static int rtas_ibm_platform_dump(struct ibm_platform_dump_params *params,
 91				phys_addr_t buf_addr, u32 buf_length)
 92{
 93	u32 rets[4];
 94	s32 fwrc;
 95	int ret = 0;
 96
 97	do {
 98		fwrc = rtas_call(rtas_function_token(RTAS_FN_IBM_PLATFORM_DUMP),
 99				6, 5,
100				rets,
101				params->dump_tag_hi,
102				params->dump_tag_lo,
103				params->sequence_hi,
104				params->sequence_lo,
105				buf_addr,
106				buf_length);
107	} while (rtas_busy_delay(fwrc));
108
109	switch (fwrc) {
110	case RTAS_HARDWARE_ERROR:
111		ret = -EIO;
112		break;
113	case RTAS_NOT_AUTHORIZED:
114		ret = -EPERM;
115		break;
116	case RTAS_IBM_PLATFORM_DUMP_CONTINUE:
117	case RTAS_IBM_PLATFORM_DUMP_COMPLETE:
118		params->sequence_hi = rets[0];
119		params->sequence_lo = rets[1];
120		params->bytes_ret_hi = rets[2];
121		params->bytes_ret_lo = rets[3];
122		break;
123	default:
124		ret = -EIO;
125		pr_err_ratelimited("unexpected ibm,platform-dump status %d\n",
126				fwrc);
127		break;
128	}
129
130	params->status = fwrc;
131	return ret;
132}
133
134/*
135 * Platform dump is used with multiple RTAS calls to retrieve the
136 * complete dump for the provided dump ID. Once the complete dump is
137 * retrieved, the hypervisor returns dump complete status (0) for the
138 * last RTAS call and expects the caller issues one more call with
139 * NULL buffer to invalidate the dump so that the hypervisor can remove
140 * the dump.
141 *
142 * After the specific dump is invalidated in the hypervisor, expect the
143 * dump complete status for the new sequence - the user space initiates
144 * new request for the same dump ID.
145 */
146static ssize_t papr_platform_dump_handle_read(struct file *file,
147		char __user *buf, size_t size, loff_t *off)
148{
149	struct ibm_platform_dump_params *params = file->private_data;
150	u64 total_bytes;
151	s32 fwrc;
152
153	/*
154	 * Dump already completed with the previous read calls.
155	 * In case if the user space issues further reads, returns
156	 * -EINVAL.
157	 */
158	if (!params->buf_length) {
159		pr_warn_once("Platform dump completed for dump ID %llu\n",
160			(u64) (((u64)params->dump_tag_hi << 32) |
161				params->dump_tag_lo));
162		return -EINVAL;
163	}
164
165	/*
166	 * The hypervisor returns status 0 if no more data available to
167	 * download. The dump will be invalidated with ioctl (see below).
168	 */
169	if (params->status == RTAS_IBM_PLATFORM_DUMP_COMPLETE) {
170		params->buf_length = 0;
171		/*
172		 * Returns 0 to the user space so that user
173		 * space read stops.
174		 */
175		return 0;
176	}
177
178	if (size < SZ_1K) {
179		pr_err_once("Buffer length should be minimum 1024 bytes\n");
180		return -EINVAL;
181	} else if (size > params->buf_length) {
182		/*
183		 * Allocate 4K work area. So if the user requests > 4K,
184		 * resize the buffer length.
185		 */
186		size = params->buf_length;
187	}
188
189	fwrc = rtas_ibm_platform_dump(params,
190			rtas_work_area_phys(params->work_area),
191			size);
192	if (fwrc < 0)
193		return fwrc;
194
195	total_bytes = (u64) (((u64)params->bytes_ret_hi << 32) |
196			params->bytes_ret_lo);
197
198	/*
199	 * Kernel or firmware bug, do not continue.
200	 */
201	if (WARN(total_bytes > size, "possible write beyond end of work area"))
202		return -EFAULT;
203
204	if (copy_to_user(buf, rtas_work_area_raw_buf(params->work_area),
205			total_bytes))
206		return -EFAULT;
207
208	return total_bytes;
209}
210
211static int papr_platform_dump_handle_release(struct inode *inode,
212					struct file *file)
213{
214	struct ibm_platform_dump_params *params = file->private_data;
215
216	if (params->work_area)
217		rtas_work_area_free(params->work_area);
218
219	mutex_lock(&platform_dump_list_mutex);
220	list_del(&params->list);
221	mutex_unlock(&platform_dump_list_mutex);
222
223	kfree(params);
224	file->private_data = NULL;
225	return 0;
226}
227
228/*
229 * This ioctl is used to invalidate the dump assuming the user space
230 * issue this ioctl after obtain the complete dump.
231 * Issue the last RTAS call with NULL buffer to invalidate the dump
232 * which means dump will be freed in the hypervisor.
233 */
234static long papr_platform_dump_invalidate_ioctl(struct file *file,
235				unsigned int ioctl, unsigned long arg)
236{
237	struct ibm_platform_dump_params *params;
238	u64 __user *argp = (void __user *)arg;
239	u64 param_dump_tag, dump_tag;
240
241	if (ioctl != PAPR_PLATFORM_DUMP_IOC_INVALIDATE)
242		return -ENOIOCTLCMD;
243
244	if (get_user(dump_tag, argp))
245		return -EFAULT;
246
247	/*
248	 * private_data is freeded during release(), so should not
249	 * happen.
250	 */
251	if (!file->private_data) {
252		pr_err("No valid FD to invalidate dump for the ID(%llu)\n",
253				dump_tag);
254		return -EINVAL;
255	}
256
257	params = file->private_data;
258	param_dump_tag = (u64) (((u64)params->dump_tag_hi << 32) |
259				params->dump_tag_lo);
260	if (dump_tag != param_dump_tag) {
261		pr_err("Invalid dump ID(%llu) to invalidate dump\n",
262				dump_tag);
263		return -EINVAL;
264	}
265
266	if (params->status != RTAS_IBM_PLATFORM_DUMP_COMPLETE) {
267		pr_err("Platform dump is not complete, but requested "
268			"to invalidate dump for ID(%llu)\n",
269			dump_tag);
270		return -EINPROGRESS;
271	}
272
273	return rtas_ibm_platform_dump(params, 0, 0);
274}
275
276static const struct file_operations papr_platform_dump_handle_ops = {
277	.read = papr_platform_dump_handle_read,
278	.release = papr_platform_dump_handle_release,
279	.unlocked_ioctl	= papr_platform_dump_invalidate_ioctl,
280};
281
282/**
283 * papr_platform_dump_create_handle() - Create a fd-based handle for
284 * reading platform dump
285 *
286 * Handler for PAPR_PLATFORM_DUMP_IOC_CREATE_HANDLE ioctl command
287 * Allocates RTAS parameter struct and work area and attached to the
288 * file descriptor for reading by user space with the multiple RTAS
289 * calls until the dump is completed. This memory allocation is freed
290 * when the file is released.
291 *
292 * Multiple dump requests with different IDs are allowed at the same
293 * time, but not with the same dump ID. So if the user space is
294 * already opened file descriptor for the specific dump ID, return
295 * -EALREADY for the next request.
296 *
297 * @dump_tag: Dump ID for the dump requested to retrieve from the
298 *		hypervisor
299 *
300 * Return: The installed fd number if successful, -ve errno otherwise.
301 */
302static long papr_platform_dump_create_handle(u64 dump_tag)
303{
304	struct ibm_platform_dump_params *params;
305	u64 param_dump_tag;
306	int fd;
307
308	/*
309	 * Return failure if the user space is already opened FD for
310	 * the specific dump ID. This check will prevent multiple dump
311	 * requests for the same dump ID at the same time. Generally
312	 * should not expect this, but in case.
313	 */
314	list_for_each_entry(params, &platform_dump_list, list) {
315		param_dump_tag = (u64) (((u64)params->dump_tag_hi << 32) |
316					params->dump_tag_lo);
317		if (dump_tag == param_dump_tag) {
318			pr_err("Platform dump for ID(%llu) is already in progress\n",
319					dump_tag);
320			return -EALREADY;
321		}
322	}
323
324	params =  kzalloc(sizeof(struct ibm_platform_dump_params),
325			GFP_KERNEL_ACCOUNT);
326	if (!params)
327		return -ENOMEM;
328
329	params->work_area = rtas_work_area_alloc(SZ_4K);
330	params->buf_length = SZ_4K;
331	params->dump_tag_hi = (u32)(dump_tag >> 32);
332	params->dump_tag_lo = (u32)(dump_tag & 0x00000000ffffffffULL);
333	params->status = RTAS_IBM_PLATFORM_DUMP_START;
334
335	fd = FD_ADD(O_RDONLY | O_CLOEXEC,
336		    anon_inode_getfile_fmode("[papr-platform-dump]",
337					     &papr_platform_dump_handle_ops,
338					     (void *)params, O_RDONLY,
339					     FMODE_LSEEK | FMODE_PREAD));
340	if (fd < 0) {
341		rtas_work_area_free(params->work_area);
342		kfree(params);
343		return fd;
344	}
345
346	list_add(&params->list, &platform_dump_list);
347
348	pr_info("%s (%d) initiated platform dump for dump tag %llu\n",
349		current->comm, current->pid, dump_tag);
350	return fd;
351}
352
353/*
354 * Top-level ioctl handler for /dev/papr-platform-dump.
355 */
356static long papr_platform_dump_dev_ioctl(struct file *filp,
357					unsigned int ioctl,
358					unsigned long arg)
359{
360	u64 __user *argp = (void __user *)arg;
361	u64 dump_tag;
362	long ret;
363
364	if (get_user(dump_tag, argp))
365		return -EFAULT;
366
367	switch (ioctl) {
368	case PAPR_PLATFORM_DUMP_IOC_CREATE_HANDLE:
369		mutex_lock(&platform_dump_list_mutex);
370		ret = papr_platform_dump_create_handle(dump_tag);
371		mutex_unlock(&platform_dump_list_mutex);
372		break;
373	default:
374		ret = -ENOIOCTLCMD;
375		break;
376	}
377	return ret;
378}
379
380static const struct file_operations papr_platform_dump_ops = {
381	.unlocked_ioctl = papr_platform_dump_dev_ioctl,
382};
383
384static struct miscdevice papr_platform_dump_dev = {
385	.minor = MISC_DYNAMIC_MINOR,
386	.name = "papr-platform-dump",
387	.fops = &papr_platform_dump_ops,
388};
389
390static __init int papr_platform_dump_init(void)
391{
392	if (!rtas_function_implemented(RTAS_FN_IBM_PLATFORM_DUMP))
393		return -ENODEV;
394
395	return misc_register(&papr_platform_dump_dev);
396}
397machine_device_initcall(pseries, papr_platform_dump_init);
~/ Read-only file preview.