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>
25 #include <linux/fdtable.h>
27 #include <linux/gfp.h>
28 #include <linux/list.h>
29 #include <linux/module.h>
30 #include <linux/syscalls.h>
32 #include <asm/uaccess.h>
36 static ssize_t
do_coredump_read(int num
, struct spu_context
*ctx
, void *buffer
,
37 size_t size
, loff_t
*off
)
42 if (spufs_coredump_read
[num
].read
)
43 return spufs_coredump_read
[num
].read(ctx
, buffer
, size
, off
);
45 data
= spufs_coredump_read
[num
].get(ctx
);
46 ret
= snprintf(buffer
, size
, "0x%.16llx", data
);
49 return ++ret
; /* count trailing NULL */
53 * These are the only things you should do on a core-file: use only these
54 * functions to write out all the necessary info.
56 static int spufs_dump_write(struct file
*file
, const void *addr
, int nr
, loff_t
*foffset
)
58 unsigned long limit
= rlimit(RLIMIT_CORE
);
61 if (*foffset
+ nr
> limit
)
64 written
= file
->f_op
->write(file
, addr
, nr
, &file
->f_pos
);
73 static int spufs_dump_align(struct file
*file
, char *buf
, loff_t new_off
,
78 size
= min((loff_t
)PAGE_SIZE
, new_off
- *foffset
);
82 while (rc
== 0 && new_off
> *foffset
) {
83 size
= min((loff_t
)PAGE_SIZE
, new_off
- *foffset
);
84 rc
= spufs_dump_write(file
, buf
, size
, foffset
);
90 static int spufs_ctx_note_size(struct spu_context
*ctx
, int dfd
)
96 for (i
= 0; spufs_coredump_read
[i
].name
!= NULL
; i
++) {
97 name
= spufs_coredump_read
[i
].name
;
98 sz
= spufs_coredump_read
[i
].size
;
100 sprintf(fullname
, "SPU/%d/%s", dfd
, name
);
102 total
+= sizeof(struct elf_note
);
103 total
+= roundup(strlen(fullname
) + 1, 4);
104 total
+= roundup(sz
, 4);
111 * The additional architecture-specific notes for Cell are various
112 * context files in the spu context.
114 * This function iterates over all open file descriptors and sees
115 * if they are a directory in spufs. In that case we use spufs
116 * internal functionality to dump them without needing to actually
119 static struct spu_context
*coredump_next_context(int *fd
)
121 struct fdtable
*fdt
= files_fdtable(current
->files
);
123 struct spu_context
*ctx
= NULL
;
125 for (; *fd
< fdt
->max_fds
; (*fd
)++) {
126 if (!FD_ISSET(*fd
, fdt
->open_fds
))
131 if (!file
|| file
->f_op
!= &spufs_context_fops
)
134 ctx
= SPUFS_I(file
->f_dentry
->d_inode
)->i_ctx
;
135 if (ctx
->flags
& SPU_CREATE_NOSCHED
)
144 int spufs_coredump_extra_notes_size(void)
146 struct spu_context
*ctx
;
147 int size
= 0, rc
, fd
;
150 while ((ctx
= coredump_next_context(&fd
)) != NULL
) {
151 rc
= spu_acquire_saved(ctx
);
154 rc
= spufs_ctx_note_size(ctx
, fd
);
155 spu_release_saved(ctx
);
161 /* start searching the next fd next time */
168 static int spufs_arch_write_note(struct spu_context
*ctx
, int i
,
169 struct file
*file
, int dfd
, loff_t
*foffset
)
172 int sz
, rc
, nread
, total
= 0;
173 const int bufsz
= PAGE_SIZE
;
175 char fullname
[80], *buf
;
178 buf
= (void *)get_zeroed_page(GFP_KERNEL
);
182 name
= spufs_coredump_read
[i
].name
;
183 sz
= spufs_coredump_read
[i
].size
;
185 sprintf(fullname
, "SPU/%d/%s", dfd
, name
);
186 en
.n_namesz
= strlen(fullname
) + 1;
190 rc
= spufs_dump_write(file
, &en
, sizeof(en
), foffset
);
194 rc
= spufs_dump_write(file
, fullname
, en
.n_namesz
, foffset
);
198 rc
= spufs_dump_align(file
, buf
, roundup(*foffset
, 4), foffset
);
203 nread
= do_coredump_read(i
, ctx
, buf
, bufsz
, &pos
);
205 rc
= spufs_dump_write(file
, buf
, nread
, foffset
);
210 } while (nread
== bufsz
&& total
< sz
);
217 rc
= spufs_dump_align(file
, buf
, roundup(*foffset
- total
+ sz
, 4),
221 free_page((unsigned long)buf
);
225 int spufs_coredump_extra_notes_write(struct file
*file
, loff_t
*foffset
)
227 struct spu_context
*ctx
;
231 while ((ctx
= coredump_next_context(&fd
)) != NULL
) {
232 rc
= spu_acquire_saved(ctx
);
236 for (j
= 0; spufs_coredump_read
[j
].name
!= NULL
; j
++) {
237 rc
= spufs_arch_write_note(ctx
, j
, file
, fd
, foffset
);
239 spu_release_saved(ctx
);
244 spu_release_saved(ctx
);
246 /* start searching the next fd next time */