4 * (C) Copyright 2006 IBM Corp.
6 * Author: Dwayne Grant McConnell <decimal@us.ibm.com>
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)
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.
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.
23 #include <linux/elf.h>
24 #include <linux/file.h>
26 #include <linux/list.h>
27 #include <linux/module.h>
28 #include <linux/syscalls.h>
30 #include <asm/uaccess.h>
34 struct spufs_ctx_info
{
35 struct list_head list
;
37 int memsize
; /* in bytes */
38 struct spu_context
*ctx
;
41 static LIST_HEAD(ctx_info_list
);
43 static ssize_t
do_coredump_read(int num
, struct spu_context
*ctx
, void __user
*buffer
,
44 size_t size
, loff_t
*off
)
49 if (spufs_coredump_read
[num
].read
)
50 return spufs_coredump_read
[num
].read(ctx
, buffer
, size
, off
);
52 data
= spufs_coredump_read
[num
].get(ctx
);
53 ret
= copy_to_user(buffer
, &data
, 8);
54 return ret
? -EFAULT
: 8;
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.
61 static int spufs_dump_write(struct file
*file
, const void *addr
, int nr
)
63 return file
->f_op
->write(file
, addr
, nr
, &file
->f_pos
) == nr
;
66 static int spufs_dump_seek(struct file
*file
, loff_t off
)
68 if (file
->f_op
->llseek
) {
69 if (file
->f_op
->llseek(file
, off
, 0) != off
)
76 static void spufs_fill_memsize(struct spufs_ctx_info
*ctx_info
)
78 struct spu_context
*ctx
;
79 unsigned long long lslr
;
82 lslr
= ctx
->csa
.priv2
.spu_lslr_RW
;
83 ctx_info
->memsize
= lslr
+ 1;
86 static int spufs_ctx_note_size(struct spufs_ctx_info
*ctx_info
)
88 int dfd
, memsize
, i
, sz
, total
= 0;
93 memsize
= ctx_info
->memsize
;
95 for (i
= 0; spufs_coredump_read
[i
].name
; i
++) {
96 name
= spufs_coredump_read
[i
].name
;
97 sz
= spufs_coredump_read
[i
].size
;
99 sprintf(fullname
, "SPU/%d/%s", dfd
, name
);
101 total
+= sizeof(struct elf_note
);
102 total
+= roundup(strlen(fullname
) + 1, 4);
103 if (!strcmp(name
, "mem"))
104 total
+= roundup(memsize
, 4);
106 total
+= roundup(sz
, 4);
112 static int spufs_add_one_context(struct file
*file
, int dfd
)
114 struct spu_context
*ctx
;
115 struct spufs_ctx_info
*ctx_info
;
118 ctx
= SPUFS_I(file
->f_dentry
->d_inode
)->i_ctx
;
119 if (ctx
->flags
& SPU_CREATE_NOSCHED
)
122 ctx_info
= kzalloc(sizeof(*ctx_info
), GFP_KERNEL
);
123 if (unlikely(!ctx_info
))
129 spufs_fill_memsize(ctx_info
);
131 size
= spufs_ctx_note_size(ctx_info
);
132 list_add(&ctx_info
->list
, &ctx_info_list
);
137 * The additional architecture-specific notes for Cell are various
138 * context files in the spu context.
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
145 static int spufs_arch_notes_size(void)
147 struct fdtable
*fdt
= files_fdtable(current
->files
);
150 for (fd
= 0; fd
< fdt
->max_fds
; fd
++) {
151 if (FD_ISSET(fd
, fdt
->open_fds
)) {
152 struct file
*file
= fcheck(fd
);
154 if (file
&& file
->f_op
== &spufs_context_fops
) {
155 int rval
= spufs_add_one_context(file
, fd
);
166 static void spufs_arch_write_note(struct spufs_ctx_info
*ctx_info
, int i
,
169 struct spu_context
*ctx
;
171 int sz
, dfd
, rc
, total
= 0;
172 const int bufsz
= PAGE_SIZE
;
174 char fullname
[80], *buf
;
177 buf
= (void *)get_zeroed_page(GFP_KERNEL
);
182 name
= spufs_coredump_read
[i
].name
;
184 if (!strcmp(name
, "mem"))
185 sz
= ctx_info
->memsize
;
187 sz
= spufs_coredump_read
[i
].size
;
193 sprintf(fullname
, "SPU/%d/%s", dfd
, name
);
194 en
.n_namesz
= strlen(fullname
) + 1;
198 if (!spufs_dump_write(file
, &en
, sizeof(en
)))
200 if (!spufs_dump_write(file
, fullname
, en
.n_namesz
))
202 if (!spufs_dump_seek(file
, roundup((unsigned long)file
->f_pos
, 4)))
206 rc
= do_coredump_read(i
, ctx
, buf
, bufsz
, &pos
);
208 if (!spufs_dump_write(file
, buf
, rc
))
212 } while (rc
== bufsz
&& total
< sz
);
214 spufs_dump_seek(file
, roundup((unsigned long)file
->f_pos
217 free_page((unsigned long)buf
);
220 static void spufs_arch_write_notes(struct file
*file
)
223 struct spufs_ctx_info
*ctx_info
, *next
;
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
);
235 struct 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
,