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/syscalls.h>
31 #include <asm/uaccess.h>
35 static ssize_t
do_coredump_read(int num
, struct spu_context
*ctx
, void *buffer
,
36 size_t size
, loff_t
*off
)
41 if (spufs_coredump_read
[num
].read
)
42 return spufs_coredump_read
[num
].read(ctx
, buffer
, size
, off
);
44 data
= spufs_coredump_read
[num
].get(ctx
);
45 ret
= snprintf(buffer
, size
, "0x%.16llx", data
);
48 return ++ret
; /* count trailing NULL */
52 * These are the only things you should do on a core-file: use only these
53 * functions to write out all the necessary info.
55 static int spufs_dump_write(struct file
*file
, const void *addr
, int nr
, loff_t
*foffset
)
57 unsigned long limit
= rlimit(RLIMIT_CORE
);
60 if (*foffset
+ nr
> limit
)
63 written
= file
->f_op
->write(file
, addr
, nr
, &file
->f_pos
);
72 static int spufs_dump_align(struct file
*file
, char *buf
, loff_t new_off
,
77 size
= min((loff_t
)PAGE_SIZE
, new_off
- *foffset
);
81 while (rc
== 0 && new_off
> *foffset
) {
82 size
= min((loff_t
)PAGE_SIZE
, new_off
- *foffset
);
83 rc
= spufs_dump_write(file
, buf
, size
, foffset
);
89 static int spufs_ctx_note_size(struct spu_context
*ctx
, int dfd
)
95 for (i
= 0; spufs_coredump_read
[i
].name
!= NULL
; 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 total
+= roundup(sz
, 4);
110 * The additional architecture-specific notes for Cell are various
111 * context files in the spu context.
113 * This function iterates over all open file descriptors and sees
114 * if they are a directory in spufs. In that case we use spufs
115 * internal functionality to dump them without needing to actually
118 static struct spu_context
*coredump_next_context(int *fd
)
120 struct fdtable
*fdt
= files_fdtable(current
->files
);
122 struct spu_context
*ctx
= NULL
;
124 for (; *fd
< fdt
->max_fds
; (*fd
)++) {
125 if (!FD_ISSET(*fd
, fdt
->open_fds
))
130 if (!file
|| file
->f_op
!= &spufs_context_fops
)
133 ctx
= SPUFS_I(file
->f_dentry
->d_inode
)->i_ctx
;
134 if (ctx
->flags
& SPU_CREATE_NOSCHED
)
143 int spufs_coredump_extra_notes_size(void)
145 struct spu_context
*ctx
;
146 int size
= 0, rc
, fd
;
149 while ((ctx
= coredump_next_context(&fd
)) != NULL
) {
150 rc
= spu_acquire_saved(ctx
);
153 rc
= spufs_ctx_note_size(ctx
, fd
);
154 spu_release_saved(ctx
);
160 /* start searching the next fd next time */
167 static int spufs_arch_write_note(struct spu_context
*ctx
, int i
,
168 struct file
*file
, int dfd
, loff_t
*foffset
)
171 int sz
, rc
, nread
, total
= 0;
172 const int bufsz
= PAGE_SIZE
;
174 char fullname
[80], *buf
;
177 buf
= (void *)get_zeroed_page(GFP_KERNEL
);
181 name
= spufs_coredump_read
[i
].name
;
182 sz
= spufs_coredump_read
[i
].size
;
184 sprintf(fullname
, "SPU/%d/%s", dfd
, name
);
185 en
.n_namesz
= strlen(fullname
) + 1;
189 rc
= spufs_dump_write(file
, &en
, sizeof(en
), foffset
);
193 rc
= spufs_dump_write(file
, fullname
, en
.n_namesz
, foffset
);
197 rc
= spufs_dump_align(file
, buf
, roundup(*foffset
, 4), foffset
);
202 nread
= do_coredump_read(i
, ctx
, buf
, bufsz
, &pos
);
204 rc
= spufs_dump_write(file
, buf
, nread
, foffset
);
209 } while (nread
== bufsz
&& total
< sz
);
216 rc
= spufs_dump_align(file
, buf
, roundup(*foffset
- total
+ sz
, 4),
220 free_page((unsigned long)buf
);
224 int spufs_coredump_extra_notes_write(struct file
*file
, loff_t
*foffset
)
226 struct spu_context
*ctx
;
230 while ((ctx
= coredump_next_context(&fd
)) != NULL
) {
231 rc
= spu_acquire_saved(ctx
);
235 for (j
= 0; spufs_coredump_read
[j
].name
!= NULL
; j
++) {
236 rc
= spufs_arch_write_note(ctx
, j
, file
, fd
, foffset
);
238 spu_release_saved(ctx
);
243 spu_release_saved(ctx
);
245 /* start searching the next fd next time */