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 static ssize_t
do_coredump_read(int num
, struct spu_context
*ctx
, void *buffer
,
35 size_t size
, loff_t
*off
)
40 if (spufs_coredump_read
[num
].read
)
41 return spufs_coredump_read
[num
].read(ctx
, buffer
, size
, off
);
43 data
= spufs_coredump_read
[num
].get(ctx
);
44 ret
= snprintf(buffer
, size
, "0x%.16lx", data
);
47 return ++ret
; /* count trailing NULL */
51 * These are the only things you should do on a core-file: use only these
52 * functions to write out all the necessary info.
54 static int spufs_dump_write(struct file
*file
, const void *addr
, int nr
, loff_t
*foffset
)
56 unsigned long limit
= current
->signal
->rlim
[RLIMIT_CORE
].rlim_cur
;
59 if (*foffset
+ nr
> limit
)
62 written
= file
->f_op
->write(file
, addr
, nr
, &file
->f_pos
);
71 static int spufs_dump_align(struct file
*file
, char *buf
, loff_t new_off
,
76 size
= min((loff_t
)PAGE_SIZE
, new_off
- *foffset
);
80 while (rc
== 0 && new_off
> *foffset
) {
81 size
= min((loff_t
)PAGE_SIZE
, new_off
- *foffset
);
82 rc
= spufs_dump_write(file
, buf
, size
, foffset
);
88 static int spufs_ctx_note_size(struct spu_context
*ctx
, int dfd
)
94 for (i
= 0; spufs_coredump_read
[i
].name
!= NULL
; i
++) {
95 name
= spufs_coredump_read
[i
].name
;
96 sz
= spufs_coredump_read
[i
].size
;
98 sprintf(fullname
, "SPU/%d/%s", dfd
, name
);
100 total
+= sizeof(struct elf_note
);
101 total
+= roundup(strlen(fullname
) + 1, 4);
102 total
+= roundup(sz
, 4);
109 * The additional architecture-specific notes for Cell are various
110 * context files in the spu context.
112 * This function iterates over all open file descriptors and sees
113 * if they are a directory in spufs. In that case we use spufs
114 * internal functionality to dump them without needing to actually
117 static struct spu_context
*coredump_next_context(int *fd
)
119 struct fdtable
*fdt
= files_fdtable(current
->files
);
121 struct spu_context
*ctx
= NULL
;
123 for (; *fd
< fdt
->max_fds
; (*fd
)++) {
124 if (!FD_ISSET(*fd
, fdt
->open_fds
))
129 if (!file
|| file
->f_op
!= &spufs_context_fops
)
132 ctx
= SPUFS_I(file
->f_dentry
->d_inode
)->i_ctx
;
133 if (ctx
->flags
& SPU_CREATE_NOSCHED
)
136 /* start searching the next fd next time we're called */
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
);
165 static int spufs_arch_write_note(struct spu_context
*ctx
, int i
,
166 struct file
*file
, int dfd
, loff_t
*foffset
)
169 int sz
, rc
, nread
, total
= 0;
170 const int bufsz
= PAGE_SIZE
;
172 char fullname
[80], *buf
;
175 buf
= (void *)get_zeroed_page(GFP_KERNEL
);
179 name
= spufs_coredump_read
[i
].name
;
180 sz
= spufs_coredump_read
[i
].size
;
182 sprintf(fullname
, "SPU/%d/%s", dfd
, name
);
183 en
.n_namesz
= strlen(fullname
) + 1;
187 rc
= spufs_dump_write(file
, &en
, sizeof(en
), foffset
);
191 rc
= spufs_dump_write(file
, fullname
, en
.n_namesz
, foffset
);
195 rc
= spufs_dump_align(file
, buf
, roundup(*foffset
, 4), foffset
);
200 nread
= do_coredump_read(i
, ctx
, buf
, bufsz
, &pos
);
202 rc
= spufs_dump_write(file
, buf
, nread
, foffset
);
207 } while (nread
== bufsz
&& total
< sz
);
214 rc
= spufs_dump_align(file
, buf
, roundup(*foffset
- total
+ sz
, 4),
218 free_page((unsigned long)buf
);
222 int spufs_coredump_extra_notes_write(struct file
*file
, loff_t
*foffset
)
224 struct spu_context
*ctx
;
228 while ((ctx
= coredump_next_context(&fd
)) != NULL
) {
229 rc
= spu_acquire_saved(ctx
);
233 for (j
= 0; spufs_coredump_read
[j
].name
!= NULL
; j
++) {
234 rc
= spufs_arch_write_note(ctx
, j
, file
, fd
, foffset
);
236 spu_release_saved(ctx
);
241 spu_release_saved(ctx
);