2 * Copyright (c) 2010-2011 by Luc Verhaegen <libv@codethink.co.uk>
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <linux/mutex.h>
20 #include <linux/uaccess.h>
21 #include <linux/debugfs.h>
24 #include "services_headers.h"
25 #include "pvr_pdump.h"
26 #include "pvr_pdumpfs.h"
28 static struct mutex pdumpfs_mutex[1];
31 PDUMPFS_MODE_DISABLED,
32 PDUMPFS_MODE_STANDARD,
36 static enum pdumpfs_mode pdumpfs_mode =
37 #if defined(CONFIG_PVR_PDUMP_MODE_STANDARD)
39 #elif defined(CONFIG_PVR_PDUMP_MODE_FULL)
46 #define FRAME_PAGE_COUNT 2040
48 struct pdumpfs_frame {
49 struct pdumpfs_frame *next;
56 unsigned long pages[FRAME_PAGE_COUNT];
59 #define MAX_FRAME_COUNT_HARD 1024
60 static u32 frame_count_max = CONFIG_PVR_PDUMP_INITIAL_MAX_FRAME_COUNT;
61 static u32 frame_count;
63 static struct pdumpfs_frame *frame_init;
64 static struct pdumpfs_frame *frame_stream;
65 static struct pdumpfs_frame *frame_current;
67 static struct pdumpfs_frame *frame_current_debugfs;
68 static int frame_current_open_count;
69 static int frame_stream_open_count;
71 static loff_t stream_start;
72 static loff_t stream_f_pos;
73 static loff_t stream_end;
75 static struct pdumpfs_frame *
78 struct pdumpfs_frame *frame =
79 kmalloc(sizeof(struct pdumpfs_frame), GFP_KERNEL);
83 memset(frame, 0, sizeof(struct pdumpfs_frame));
89 frame_destroy(struct pdumpfs_frame *frame)
96 for (i = 0; i < frame->page_count; i++)
97 free_page(frame->pages[i]);
103 frame_destroy_all(void)
105 /* detach from possible clones */
106 if (frame_current_debugfs &&
107 ((frame_current_debugfs == frame_init) ||
108 (frame_current_debugfs == frame_current) ||
109 frame_current_debugfs->next))
110 frame_current_debugfs = NULL;
112 frame_current = NULL;
114 frame_destroy(frame_init);
117 frame_destroy(frame_current_debugfs);
118 frame_current_debugfs = NULL;
120 while (frame_stream) {
121 struct pdumpfs_frame *frame = frame_stream;
123 frame_stream = frame->next;
125 frame_destroy(frame);
135 frame_cull_first(void)
137 struct pdumpfs_frame *frame = frame_stream;
139 frame_stream = frame->next;
142 if (frame_stream_open_count)
143 stream_start += frame->offset;
145 stream_end -= frame->offset;
148 * we cannot have frames vanish in the middle of reading
149 * them through debugfs
151 if (frame != frame_current_debugfs)
152 frame_destroy(frame);
161 if (!frame_stream_open_count) {
162 while (frame_count > frame_count_max)
165 while (((stream_start + frame_stream->offset) < stream_f_pos) ||
166 (frame_count > MAX_FRAME_COUNT_HARD))
172 frame_new(u32 pid, u32 number)
174 struct pdumpfs_frame *frame = frame_create();
177 pr_err("%s: Failed to create frame.\n", __func__);
182 frame->number = number;
187 if (frame_current != frame_init)
188 frame_current->next = frame;
190 frame_stream = frame;
194 frame_current = frame;
202 pdumpfs_frame_set(u32 pid, u32 frame)
204 mutex_lock(pdumpfs_mutex);
206 frame_new(pid, frame);
208 mutex_unlock(pdumpfs_mutex);
212 pdumpfs_capture_enabled(void)
216 mutex_lock(pdumpfs_mutex);
218 if (pdumpfs_mode == PDUMPFS_MODE_FULL)
223 mutex_unlock(pdumpfs_mutex);
229 pdumpfs_flags_check(u32 flags)
233 if (flags & PDUMP_FLAGS_NEVER)
236 mutex_lock(pdumpfs_mutex);
238 if (pdumpfs_mode == PDUMPFS_MODE_FULL)
240 else if ((pdumpfs_mode == PDUMPFS_MODE_STANDARD) &&
241 (flags & PDUMP_FLAGS_CONTINUOUS))
246 mutex_unlock(pdumpfs_mutex);
252 pdumpfs_frame_write_low(void *buffer, size_t size, bool from_user)
254 struct pdumpfs_frame *frame = frame_current;
259 size_t offset = frame->offset & ~PAGE_MASK;
263 if (frame->page_count >= FRAME_PAGE_COUNT) {
264 pr_err("%s: Frame size overrun.\n", __func__);
268 page = __get_free_page(GFP_KERNEL);
270 pr_err("%s: failed to get free page.\n",
275 frame->pages[frame->page_count] = page;
279 frame->pages[frame->page_count - 1];
281 if (count > (PAGE_SIZE - offset))
282 count = PAGE_SIZE - offset;
285 if (copy_from_user(((u8 *) page) + offset,
286 (void __user __force *) buffer,
290 memcpy(((u8 *) page) + offset, buffer, count);
295 frame->offset += count;
301 pdumpfs_frame_write(void *buffer, size_t size, bool from_user)
305 if ((frame_current->offset + size) > (PAGE_SIZE * FRAME_PAGE_COUNT)) {
306 u32 pid = OSGetCurrentProcessIDKM();
307 struct task_struct *task;
309 pr_err("Frame overrun!!!\n");
311 ret = frame_new(pid, -1);
316 task = pid_task(find_vpid(pid), PIDTYPE_PID);
318 #define FRAME_OVERRUN_MESSAGE "-- Starting forced frame caused by "
319 pdumpfs_frame_write_low(FRAME_OVERRUN_MESSAGE,
320 sizeof(FRAME_OVERRUN_MESSAGE), false);
321 pdumpfs_frame_write_low(task->comm, strlen(task->comm), false);
322 pdumpfs_frame_write_low("\r\n", 2, false);
324 pr_err("%s: Frame size overrun, caused by %d (%s)\n",
325 __func__, pid, task->comm);
330 return pdumpfs_frame_write_low(buffer, size, from_user);
334 pdumpfs_write_data(void *buffer, size_t size, bool from_user)
336 mutex_lock(pdumpfs_mutex);
338 size = pdumpfs_frame_write(buffer, size, from_user);
339 if ((size > 0) && (frame_current != frame_init))
342 mutex_unlock(pdumpfs_mutex);
344 if ((size >= 0) || (size == -ENOMEM))
347 return PVRSRV_ERROR_GENERIC;
351 pdumpfs_write_string(char *string)
355 mutex_lock(pdumpfs_mutex);
357 size = pdumpfs_frame_write(string, strlen(string), false);
358 if ((size > 0) && (frame_current != frame_init))
361 mutex_unlock(pdumpfs_mutex);
367 static const struct {
369 enum pdumpfs_mode mode;
370 } pdumpfs_modes[] = {
371 {"disabled", PDUMPFS_MODE_DISABLED},
372 {"standard", PDUMPFS_MODE_STANDARD},
373 {"full", PDUMPFS_MODE_FULL},
374 {NULL, PDUMPFS_MODE_DISABLED}
378 pdumpfs_mode_read(struct file *filp, char __user *buf, size_t size,
386 mutex_lock(pdumpfs_mutex);
388 for (i = 0; pdumpfs_modes[i].name; i++)
389 if (pdumpfs_modes[i].mode == pdumpfs_mode)
390 snprintf(tmp, sizeof(tmp), "%s\n",
391 pdumpfs_modes[i].name);
393 mutex_unlock(pdumpfs_mutex);
395 if (strlen(tmp) < *f_pos)
398 if ((strlen(tmp) + 1) < (*f_pos + size))
399 size = strlen(tmp) + 1 - *f_pos;
401 if (copy_to_user(buf, tmp + *f_pos, size))
409 pdumpfs_mode_write(struct file *filp, const char __user *buf, size_t size,
415 if (*f_pos > sizeof(tmp))
418 if (size > (sizeof(tmp) - *f_pos))
419 size = sizeof(tmp) - *f_pos;
421 if (copy_from_user(tmp + *f_pos, buf, size))
426 mutex_lock(pdumpfs_mutex);
428 for (i = 0; pdumpfs_modes[i].name; i++)
429 if (!strnicmp(tmp, pdumpfs_modes[i].name,
430 strlen(pdumpfs_modes[i].name))) {
431 pdumpfs_mode = pdumpfs_modes[i].mode;
432 mutex_unlock(pdumpfs_mutex);
436 mutex_unlock(pdumpfs_mutex);
440 static const struct file_operations pdumpfs_mode_fops = {
441 .owner = THIS_MODULE,
443 .read = pdumpfs_mode_read,
444 .write = pdumpfs_mode_write,
448 pdumpfs_modes_possible_read(struct file *filp, char __user *buf, size_t size,
451 unsigned int i, skip = *f_pos, pos = 0;
453 for (i = 0; pdumpfs_modes[i].name; i++) {
457 else if (size > pos) {
458 if (copy_to_user(buf + pos, " ", 1))
465 int len = strlen(pdumpfs_modes[i].name);
469 } else if (size > pos) {
470 len = min(len - skip, size - pos);
472 if (copy_to_user(buf + pos,
473 pdumpfs_modes[i].name + skip,
487 static const struct file_operations pdumpfs_modes_possible_fops = {
488 .owner = THIS_MODULE,
490 .read = pdumpfs_modes_possible_read,
494 pdumpfs_frame_count_max_read(struct file *filp, char __user *buf, size_t size,
501 mutex_lock(pdumpfs_mutex);
502 snprintf(tmp, sizeof(tmp), "%d", frame_count_max);
503 mutex_unlock(pdumpfs_mutex);
505 if (strlen(tmp) < *f_pos)
508 if ((strlen(tmp) + 1) < (*f_pos + size))
509 size = strlen(tmp) + 1 - *f_pos;
511 if (copy_to_user(buf, tmp + *f_pos, size))
519 pdumpfs_frame_count_max_write(struct file *filp, const char __user *buf,
520 size_t size, loff_t *f_pos)
523 unsigned long result = 0;
525 if (*f_pos > sizeof(tmp))
528 if (size > (sizeof(tmp) - *f_pos))
529 size = sizeof(tmp) - *f_pos;
531 if (copy_from_user(tmp + *f_pos, buf, size))
536 mutex_lock(pdumpfs_mutex);
538 if (!strict_strtoul(tmp, 0, &result)) {
543 frame_count_max = result;
546 mutex_unlock(pdumpfs_mutex);
552 static const struct file_operations pdumpfs_frame_count_max_fops = {
553 .owner = THIS_MODULE,
555 .read = pdumpfs_frame_count_max_read,
556 .write = pdumpfs_frame_count_max_write,
560 pdumpfs_frame_read_single(struct pdumpfs_frame *frame, char __user *buf,
561 size_t size, loff_t f_pos)
566 if (f_pos >= frame->offset)
569 if (size > (frame->offset - f_pos))
570 size = frame->offset - f_pos;
572 page = f_pos / PAGE_SIZE;
573 offset = f_pos % PAGE_SIZE;
575 if (size > (PAGE_SIZE - offset))
576 size = PAGE_SIZE - offset;
578 if (copy_to_user(buf, ((u8 *) frame->pages[page]) + offset, size))
585 pdumpfs_llseek_helper(struct file *filp, loff_t offset, int whence, loff_t max)
591 if ((offset > max) || (offset < 0))
597 if (((filp->f_pos + offset) > max) ||
598 ((filp->f_pos + offset) < 0))
601 f_pos = filp->f_pos + offset;
608 f_pos = max + offset;
622 pdumpfs_init_llseek(struct file *filp, loff_t offset, int whence)
626 mutex_lock(pdumpfs_mutex);
628 f_pos = pdumpfs_llseek_helper(filp, offset, whence, frame_init->offset);
630 mutex_unlock(pdumpfs_mutex);
636 pdumpfs_init_read(struct file *filp, char __user *buf, size_t size,
639 mutex_lock(pdumpfs_mutex);
641 size = pdumpfs_frame_read_single(frame_init,
644 mutex_unlock(pdumpfs_mutex);
651 static const struct file_operations pdumpfs_init_fops = {
652 .owner = THIS_MODULE,
653 .llseek = pdumpfs_init_llseek,
654 .read = pdumpfs_init_read,
658 * We need to make sure that our frame doesn't vanish while we are still
659 * reading it: so reference this frame again.
662 pdumpfs_current_open(struct inode *inode, struct file *filp)
664 mutex_lock(pdumpfs_mutex);
666 if (!frame_current_open_count)
667 frame_current_debugfs = frame_current;
669 frame_current_open_count++;
671 mutex_unlock(pdumpfs_mutex);
676 pdumpfs_current_release(struct inode *inode, struct file *filp)
678 mutex_lock(pdumpfs_mutex);
680 frame_current_open_count--;
682 if (!frame_current_open_count) {
683 if ((frame_current_debugfs != frame_init) &&
684 (frame_current_debugfs != frame_current) &&
685 !frame_current_debugfs->next)
686 frame_destroy(frame_current_debugfs);
687 frame_current_debugfs = NULL;
690 mutex_unlock(pdumpfs_mutex);
695 pdumpfs_current_llseek(struct file *filp, loff_t offset, int whence)
699 mutex_lock(pdumpfs_mutex);
701 f_pos = pdumpfs_llseek_helper(filp, offset, whence,
702 frame_current_debugfs->offset);
704 mutex_unlock(pdumpfs_mutex);
710 pdumpfs_current_read(struct file *filp, char __user *buf, size_t size,
713 mutex_lock(pdumpfs_mutex);
715 if (frame_current_debugfs->offset)
716 size = pdumpfs_frame_read_single(frame_current_debugfs,
721 mutex_unlock(pdumpfs_mutex);
728 static const struct file_operations pdumpfs_current_fops = {
729 .owner = THIS_MODULE,
730 .llseek = pdumpfs_current_llseek,
731 .read = pdumpfs_current_read,
732 .open = pdumpfs_current_open,
733 .release = pdumpfs_current_release,
737 * So we can track when we can alter stream offsets.
740 pdumpfs_stream_open(struct inode *inode, struct file *filp)
744 mutex_lock(pdumpfs_mutex);
746 if (frame_stream_open_count)
749 frame_stream_open_count++;
753 mutex_unlock(pdumpfs_mutex);
758 pdumpfs_stream_release(struct inode *inode, struct file *filp)
760 mutex_lock(pdumpfs_mutex);
762 frame_stream_open_count--;
764 /* fix the damage done while it was open */
765 if (!frame_stream_open_count) {
766 stream_end -= stream_start;
771 mutex_unlock(pdumpfs_mutex);
776 pdumpfs_stream_buffer_clear(char __user *buf, size_t size)
780 memset(tmp, '.', sizeof(tmp) - 1);
781 tmp[sizeof(tmp) - 1] = '\n';
783 if (size >= sizeof(tmp)) {
786 for (i = 0; (i + sizeof(tmp)) < size; i += sizeof(tmp))
787 if (copy_to_user(buf + i, tmp, sizeof(tmp)))
791 if (copy_to_user(buf, tmp + sizeof(tmp) - size, size))
798 pdumpfs_stream_buffer_fill(struct pdumpfs_frame *frame,
799 char __user *buf, size_t offset, size_t size)
801 int page = offset / PAGE_SIZE;
803 if (size > (frame->offset - offset))
804 size = frame->offset - offset;
808 if (size > (PAGE_SIZE - offset))
809 size = PAGE_SIZE - offset;
811 if (copy_to_user(buf, ((u8 *) frame->pages[page]) + offset, size))
814 stream_f_pos += size;
820 pdumpfs_stream_llseek(struct file *filp, loff_t offset, int whence)
824 mutex_lock(pdumpfs_mutex);
828 if ((offset > stream_end) || (offset < stream_start))
834 if (((filp->f_pos + offset) > stream_end) ||
835 ((filp->f_pos + offset) < stream_start))
838 f_pos = filp->f_pos + offset;
842 (offset < (stream_start - stream_end)))
845 f_pos = stream_end + offset;
854 stream_f_pos = f_pos;
857 mutex_unlock(pdumpfs_mutex);
863 pdumpfs_stream_read(struct file *filp, char __user *buf, size_t size,
868 mutex_lock(pdumpfs_mutex);
870 if ((stream_end <= 0) || (*f_pos >= stream_end))
872 else if (*f_pos < stream_start) {
873 if (size > (stream_start - *f_pos))
874 size = stream_start - *f_pos;
875 ret = pdumpfs_stream_buffer_clear(buf, size);
877 loff_t start = stream_start;
878 struct pdumpfs_frame *frame = frame_stream;
880 /* skip frames that are before our offset */
881 while ((start + frame->offset) <= *f_pos) {
882 start += frame->offset;
886 ret = pdumpfs_stream_buffer_fill(frame, buf, *f_pos - start,
892 mutex_unlock(pdumpfs_mutex);
896 static const struct file_operations pdumpfs_stream_fops = {
897 .owner = THIS_MODULE,
898 .llseek = pdumpfs_stream_llseek,
899 .read = pdumpfs_stream_read,
900 .open = pdumpfs_stream_open,
901 .release = pdumpfs_stream_release,
904 static struct dentry *pdumpfs_dir;
907 pdumpfs_file_create(const char *name, mode_t mode,
908 const struct file_operations *fops)
910 struct dentry *tmp = NULL;
912 tmp = debugfs_create_file(name, mode, pdumpfs_dir, NULL, fops);
914 pr_err("%s: failed to create pvr/%s file.\n", __func__, name);
918 pdumpfs_fs_init(void)
920 if (!pvr_debugfs_dir) {
921 pr_err("%s: debugfs pvr/ directory does not exist.\n",
926 pdumpfs_dir = debugfs_create_dir("pdump", pvr_debugfs_dir);
928 pr_err("%s: failed to create top level directory.\n",
933 pdumpfs_file_create("mode", S_IRUSR | S_IWUSR,
935 pdumpfs_file_create("modes_possible", S_IRUSR,
936 &pdumpfs_modes_possible_fops);
938 pdumpfs_file_create("frame_count_max", S_IRUSR | S_IWUSR,
939 &pdumpfs_frame_count_max_fops);
941 pdumpfs_file_create("init_frame", S_IRUSR,
943 pdumpfs_file_create("current_frame", S_IRUSR,
944 &pdumpfs_current_fops);
945 pdumpfs_file_create("stream_frames", S_IRUSR,
946 &pdumpfs_stream_fops);
952 pdumpfs_fs_destroy(void)
955 debugfs_remove_recursive(pdumpfs_dir);
963 mutex_init(pdumpfs_mutex);
965 ret = frame_new(0, 0);
975 pdumpfs_cleanup(void)
977 pdumpfs_fs_destroy();