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 buf_addr: rtas_work_area_phys(params->work_area),
191 buf_length: 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(to: buf, from: rtas_work_area_raw_buf(params->work_area),
205 n: 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(entry: &params->list);
221 mutex_unlock(lock: &platform_dump_list_mutex);
222
223 kfree(objp: 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, buf_addr: 0, buf_length: 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 struct file *file;
307 long err;
308 int fd;
309
310 /*
311 * Return failure if the user space is already opened FD for
312 * the specific dump ID. This check will prevent multiple dump
313 * requests for the same dump ID at the same time. Generally
314 * should not expect this, but in case.
315 */
316 list_for_each_entry(params, &platform_dump_list, list) {
317 param_dump_tag = (u64) (((u64)params->dump_tag_hi << 32) |
318 params->dump_tag_lo);
319 if (dump_tag == param_dump_tag) {
320 pr_err("Platform dump for ID(%llu) is already in progress\n",
321 dump_tag);
322 return -EALREADY;
323 }
324 }
325
326 params = kzalloc(sizeof(struct ibm_platform_dump_params),
327 GFP_KERNEL_ACCOUNT);
328 if (!params)
329 return -ENOMEM;
330
331 params->work_area = rtas_work_area_alloc(SZ_4K);
332 params->buf_length = SZ_4K;
333 params->dump_tag_hi = (u32)(dump_tag >> 32);
334 params->dump_tag_lo = (u32)(dump_tag & 0x00000000ffffffffULL);
335 params->status = RTAS_IBM_PLATFORM_DUMP_START;
336
337 fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
338 if (fd < 0) {
339 err = fd;
340 goto free_area;
341 }
342
343 file = anon_inode_getfile_fmode(name: "[papr-platform-dump]",
344 fops: &papr_platform_dump_handle_ops,
345 priv: (void *)params, O_RDONLY,
346 FMODE_LSEEK | FMODE_PREAD);
347 if (IS_ERR(ptr: file)) {
348 err = PTR_ERR(ptr: file);
349 goto put_fd;
350 }
351
352 fd_install(fd, file);
353
354 list_add(new: &params->list, head: &platform_dump_list);
355
356 pr_info("%s (%d) initiated platform dump for dump tag %llu\n",
357 current->comm, current->pid, dump_tag);
358 return fd;
359put_fd:
360 put_unused_fd(fd);
361free_area:
362 rtas_work_area_free(params->work_area);
363 kfree(objp: params);
364 return err;
365}
366
367/*
368 * Top-level ioctl handler for /dev/papr-platform-dump.
369 */
370static long papr_platform_dump_dev_ioctl(struct file *filp,
371 unsigned int ioctl,
372 unsigned long arg)
373{
374 u64 __user *argp = (void __user *)arg;
375 u64 dump_tag;
376 long ret;
377
378 if (get_user(dump_tag, argp))
379 return -EFAULT;
380
381 switch (ioctl) {
382 case PAPR_PLATFORM_DUMP_IOC_CREATE_HANDLE:
383 mutex_lock(&platform_dump_list_mutex);
384 ret = papr_platform_dump_create_handle(dump_tag);
385 mutex_unlock(lock: &platform_dump_list_mutex);
386 break;
387 default:
388 ret = -ENOIOCTLCMD;
389 break;
390 }
391 return ret;
392}
393
394static const struct file_operations papr_platform_dump_ops = {
395 .unlocked_ioctl = papr_platform_dump_dev_ioctl,
396};
397
398static struct miscdevice papr_platform_dump_dev = {
399 .minor = MISC_DYNAMIC_MINOR,
400 .name = "papr-platform-dump",
401 .fops = &papr_platform_dump_ops,
402};
403
404static __init int papr_platform_dump_init(void)
405{
406 if (!rtas_function_implemented(RTAS_FN_IBM_PLATFORM_DUMP))
407 return -ENODEV;
408
409 return misc_register(misc: &papr_platform_dump_dev);
410}
411machine_device_initcall(pseries, papr_platform_dump_init);
412

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of linux/arch/powerpc/platforms/pseries/papr-platform-dump.c