• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/src/linux/linux-2.6/arch/powerpc/platforms/cell/spufs/
1/*
2 * SPU core dump code
3 *
4 * (C) Copyright 2006 IBM Corp.
5 *
6 * Author: Dwayne Grant McConnell <decimal@us.ibm.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23#include <linux/elf.h>
24#include <linux/file.h>
25#include <linux/fs.h>
26#include <linux/list.h>
27#include <linux/module.h>
28#include <linux/syscalls.h>
29
30#include <asm/uaccess.h>
31
32#include "spufs.h"
33
34struct spufs_ctx_info {
35	struct list_head list;
36	int dfd;
37	int memsize; /* in bytes */
38	struct spu_context *ctx;
39};
40
41static LIST_HEAD(ctx_info_list);
42
43static ssize_t do_coredump_read(int num, struct spu_context *ctx, void __user *buffer,
44				size_t size, loff_t *off)
45{
46	u64 data;
47	int ret;
48
49	if (spufs_coredump_read[num].read)
50		return spufs_coredump_read[num].read(ctx, buffer, size, off);
51
52	data = spufs_coredump_read[num].get(ctx);
53	ret = copy_to_user(buffer, &data, 8);
54	return ret ? -EFAULT : 8;
55}
56
57/*
58 * These are the only things you should do on a core-file: use only these
59 * functions to write out all the necessary info.
60 */
61static int spufs_dump_write(struct file *file, const void *addr, int nr)
62{
63	return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
64}
65
66static int spufs_dump_seek(struct file *file, loff_t off)
67{
68	if (file->f_op->llseek) {
69		if (file->f_op->llseek(file, off, 0) != off)
70			return 0;
71	} else
72		file->f_pos = off;
73	return 1;
74}
75
76static void spufs_fill_memsize(struct spufs_ctx_info *ctx_info)
77{
78	struct spu_context *ctx;
79	unsigned long long lslr;
80
81	ctx = ctx_info->ctx;
82	lslr = ctx->csa.priv2.spu_lslr_RW;
83	ctx_info->memsize = lslr + 1;
84}
85
86static int spufs_ctx_note_size(struct spufs_ctx_info *ctx_info)
87{
88	int dfd, memsize, i, sz, total = 0;
89	char *name;
90	char fullname[80];
91
92	dfd = ctx_info->dfd;
93	memsize = ctx_info->memsize;
94
95	for (i = 0; spufs_coredump_read[i].name; i++) {
96		name = spufs_coredump_read[i].name;
97		sz = spufs_coredump_read[i].size;
98
99		sprintf(fullname, "SPU/%d/%s", dfd, name);
100
101		total += sizeof(struct elf_note);
102		total += roundup(strlen(fullname) + 1, 4);
103		if (!strcmp(name, "mem"))
104			total += roundup(memsize, 4);
105		else
106			total += roundup(sz, 4);
107	}
108
109	return total;
110}
111
112static int spufs_add_one_context(struct file *file, int dfd)
113{
114	struct spu_context *ctx;
115	struct spufs_ctx_info *ctx_info;
116	int size;
117
118	ctx = SPUFS_I(file->f_dentry->d_inode)->i_ctx;
119	if (ctx->flags & SPU_CREATE_NOSCHED)
120		return 0;
121
122	ctx_info = kzalloc(sizeof(*ctx_info), GFP_KERNEL);
123	if (unlikely(!ctx_info))
124		return -ENOMEM;
125
126	ctx_info->dfd = dfd;
127	ctx_info->ctx = ctx;
128
129	spufs_fill_memsize(ctx_info);
130
131	size = spufs_ctx_note_size(ctx_info);
132	list_add(&ctx_info->list, &ctx_info_list);
133	return size;
134}
135
136/*
137 * The additional architecture-specific notes for Cell are various
138 * context files in the spu context.
139 *
140 * This function iterates over all open file descriptors and sees
141 * if they are a directory in spufs.  In that case we use spufs
142 * internal functionality to dump them without needing to actually
143 * open the files.
144 */
145static int spufs_arch_notes_size(void)
146{
147	struct fdtable *fdt = files_fdtable(current->files);
148	int size = 0, fd;
149
150	for (fd = 0; fd < fdt->max_fds; fd++) {
151		if (FD_ISSET(fd, fdt->open_fds)) {
152			struct file *file = fcheck(fd);
153
154			if (file && file->f_op == &spufs_context_fops) {
155				int rval = spufs_add_one_context(file, fd);
156				if (rval < 0)
157					break;
158				size += rval;
159			}
160		}
161	}
162
163	return size;
164}
165
166static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i,
167				struct file *file)
168{
169	struct spu_context *ctx;
170	loff_t pos = 0;
171	int sz, dfd, rc, total = 0;
172	const int bufsz = PAGE_SIZE;
173	char *name;
174	char fullname[80], *buf;
175	struct elf_note en;
176
177	buf = (void *)get_zeroed_page(GFP_KERNEL);
178	if (!buf)
179		return;
180
181	dfd = ctx_info->dfd;
182	name = spufs_coredump_read[i].name;
183
184	if (!strcmp(name, "mem"))
185		sz = ctx_info->memsize;
186	else
187		sz = spufs_coredump_read[i].size;
188
189	ctx = ctx_info->ctx;
190	if (!ctx)
191		goto out;
192
193	sprintf(fullname, "SPU/%d/%s", dfd, name);
194	en.n_namesz = strlen(fullname) + 1;
195	en.n_descsz = sz;
196	en.n_type = NT_SPU;
197
198	if (!spufs_dump_write(file, &en, sizeof(en)))
199		goto out;
200	if (!spufs_dump_write(file, fullname, en.n_namesz))
201		goto out;
202	if (!spufs_dump_seek(file, roundup((unsigned long)file->f_pos, 4)))
203		goto out;
204
205	do {
206		rc = do_coredump_read(i, ctx, buf, bufsz, &pos);
207		if (rc > 0) {
208			if (!spufs_dump_write(file, buf, rc))
209				goto out;
210			total += rc;
211		}
212	} while (rc == bufsz && total < sz);
213
214	spufs_dump_seek(file, roundup((unsigned long)file->f_pos
215						- total + sz, 4));
216out:
217	free_page((unsigned long)buf);
218}
219
220static void spufs_arch_write_notes(struct file *file)
221{
222	int j;
223	struct spufs_ctx_info *ctx_info, *next;
224
225	list_for_each_entry_safe(ctx_info, next, &ctx_info_list, list) {
226		spu_acquire_saved(ctx_info->ctx);
227		for (j = 0; j < spufs_coredump_num_notes; j++)
228			spufs_arch_write_note(ctx_info, j, file);
229		spu_release(ctx_info->ctx);
230		list_del(&ctx_info->list);
231		kfree(ctx_info);
232	}
233}
234
235struct spu_coredump_calls spufs_coredump_calls = {
236	.arch_notes_size = spufs_arch_notes_size,
237	.arch_write_notes = spufs_arch_write_notes,
238	.owner = THIS_MODULE,
239};
240