mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-03-31 19:45:21 +00:00
powerpc/spufs: fix copy_to_user while atomic
Currently, we may perform a copy_to_user (through
simple_read_from_buffer()) while holding a context's register_lock,
while accessing the context save area.
This change uses a temporary buffer for the context save area data,
which we then pass to simple_read_from_buffer.
Includes changes from Christoph Hellwig <hch@lst.de>.
Fixes: bf1ab978be
("[POWERPC] coredump: Add SPU elf notes to coredump.")
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
[hch: renamed to function to avoid ___-prefixes]
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
8f3d9f3542
commit
88413a6bfb
1 changed files with 75 additions and 38 deletions
|
@ -1978,8 +1978,9 @@ static ssize_t __spufs_mbox_info_read(struct spu_context *ctx,
|
||||||
static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
|
static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
|
||||||
size_t len, loff_t *pos)
|
size_t len, loff_t *pos)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
struct spu_context *ctx = file->private_data;
|
struct spu_context *ctx = file->private_data;
|
||||||
|
u32 stat, data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!access_ok(buf, len))
|
if (!access_ok(buf, len))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
@ -1988,11 +1989,16 @@ static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
spin_lock(&ctx->csa.register_lock);
|
spin_lock(&ctx->csa.register_lock);
|
||||||
ret = __spufs_mbox_info_read(ctx, buf, len, pos);
|
stat = ctx->csa.prob.mb_stat_R;
|
||||||
|
data = ctx->csa.prob.pu_mb_R;
|
||||||
spin_unlock(&ctx->csa.register_lock);
|
spin_unlock(&ctx->csa.register_lock);
|
||||||
spu_release_saved(ctx);
|
spu_release_saved(ctx);
|
||||||
|
|
||||||
return ret;
|
/* EOF if there's no entry in the mbox */
|
||||||
|
if (!(stat & 0x0000ff))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations spufs_mbox_info_fops = {
|
static const struct file_operations spufs_mbox_info_fops = {
|
||||||
|
@ -2019,6 +2025,7 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
|
||||||
size_t len, loff_t *pos)
|
size_t len, loff_t *pos)
|
||||||
{
|
{
|
||||||
struct spu_context *ctx = file->private_data;
|
struct spu_context *ctx = file->private_data;
|
||||||
|
u32 stat, data;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!access_ok(buf, len))
|
if (!access_ok(buf, len))
|
||||||
|
@ -2028,11 +2035,16 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
spin_lock(&ctx->csa.register_lock);
|
spin_lock(&ctx->csa.register_lock);
|
||||||
ret = __spufs_ibox_info_read(ctx, buf, len, pos);
|
stat = ctx->csa.prob.mb_stat_R;
|
||||||
|
data = ctx->csa.priv2.puint_mb_R;
|
||||||
spin_unlock(&ctx->csa.register_lock);
|
spin_unlock(&ctx->csa.register_lock);
|
||||||
spu_release_saved(ctx);
|
spu_release_saved(ctx);
|
||||||
|
|
||||||
return ret;
|
/* EOF if there's no entry in the ibox */
|
||||||
|
if (!(stat & 0xff0000))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations spufs_ibox_info_fops = {
|
static const struct file_operations spufs_ibox_info_fops = {
|
||||||
|
@ -2041,6 +2053,11 @@ static const struct file_operations spufs_ibox_info_fops = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static size_t spufs_wbox_info_cnt(struct spu_context *ctx)
|
||||||
|
{
|
||||||
|
return (4 - ((ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8)) * sizeof(u32);
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
|
static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
|
||||||
char __user *buf, size_t len, loff_t *pos)
|
char __user *buf, size_t len, loff_t *pos)
|
||||||
{
|
{
|
||||||
|
@ -2049,7 +2066,7 @@ static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
|
||||||
u32 wbox_stat;
|
u32 wbox_stat;
|
||||||
|
|
||||||
wbox_stat = ctx->csa.prob.mb_stat_R;
|
wbox_stat = ctx->csa.prob.mb_stat_R;
|
||||||
cnt = 4 - ((wbox_stat & 0x00ff00) >> 8);
|
cnt = spufs_wbox_info_cnt(ctx);
|
||||||
for (i = 0; i < cnt; i++) {
|
for (i = 0; i < cnt; i++) {
|
||||||
data[i] = ctx->csa.spu_mailbox_data[i];
|
data[i] = ctx->csa.spu_mailbox_data[i];
|
||||||
}
|
}
|
||||||
|
@ -2062,7 +2079,8 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
|
||||||
size_t len, loff_t *pos)
|
size_t len, loff_t *pos)
|
||||||
{
|
{
|
||||||
struct spu_context *ctx = file->private_data;
|
struct spu_context *ctx = file->private_data;
|
||||||
int ret;
|
u32 data[ARRAY_SIZE(ctx->csa.spu_mailbox_data)];
|
||||||
|
int ret, count;
|
||||||
|
|
||||||
if (!access_ok(buf, len))
|
if (!access_ok(buf, len))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
@ -2071,11 +2089,13 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
spin_lock(&ctx->csa.register_lock);
|
spin_lock(&ctx->csa.register_lock);
|
||||||
ret = __spufs_wbox_info_read(ctx, buf, len, pos);
|
count = spufs_wbox_info_cnt(ctx);
|
||||||
|
memcpy(&data, &ctx->csa.spu_mailbox_data, sizeof(data));
|
||||||
spin_unlock(&ctx->csa.register_lock);
|
spin_unlock(&ctx->csa.register_lock);
|
||||||
spu_release_saved(ctx);
|
spu_release_saved(ctx);
|
||||||
|
|
||||||
return ret;
|
return simple_read_from_buffer(buf, len, pos, &data,
|
||||||
|
count * sizeof(u32));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations spufs_wbox_info_fops = {
|
static const struct file_operations spufs_wbox_info_fops = {
|
||||||
|
@ -2084,27 +2104,33 @@ static const struct file_operations spufs_wbox_info_fops = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
|
static void spufs_get_dma_info(struct spu_context *ctx,
|
||||||
char __user *buf, size_t len, loff_t *pos)
|
struct spu_dma_info *info)
|
||||||
{
|
{
|
||||||
struct spu_dma_info info;
|
|
||||||
struct mfc_cq_sr *qp, *spuqp;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
|
info->dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
|
||||||
info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
|
info->dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
|
||||||
info.dma_info_status = ctx->csa.spu_chnldata_RW[24];
|
info->dma_info_status = ctx->csa.spu_chnldata_RW[24];
|
||||||
info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
|
info->dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
|
||||||
info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
|
info->dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < 16; i++) {
|
||||||
qp = &info.dma_info_command_data[i];
|
struct mfc_cq_sr *qp = &info->dma_info_command_data[i];
|
||||||
spuqp = &ctx->csa.priv2.spuq[i];
|
struct mfc_cq_sr *spuqp = &ctx->csa.priv2.spuq[i];
|
||||||
|
|
||||||
qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW;
|
qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW;
|
||||||
qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW;
|
qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW;
|
||||||
qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW;
|
qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW;
|
||||||
qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW;
|
qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
|
||||||
|
char __user *buf, size_t len, loff_t *pos)
|
||||||
|
{
|
||||||
|
struct spu_dma_info info;
|
||||||
|
|
||||||
|
spufs_get_dma_info(ctx, &info);
|
||||||
|
|
||||||
return simple_read_from_buffer(buf, len, pos, &info,
|
return simple_read_from_buffer(buf, len, pos, &info,
|
||||||
sizeof info);
|
sizeof info);
|
||||||
|
@ -2114,6 +2140,7 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
|
||||||
size_t len, loff_t *pos)
|
size_t len, loff_t *pos)
|
||||||
{
|
{
|
||||||
struct spu_context *ctx = file->private_data;
|
struct spu_context *ctx = file->private_data;
|
||||||
|
struct spu_dma_info info;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!access_ok(buf, len))
|
if (!access_ok(buf, len))
|
||||||
|
@ -2123,11 +2150,12 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
spin_lock(&ctx->csa.register_lock);
|
spin_lock(&ctx->csa.register_lock);
|
||||||
ret = __spufs_dma_info_read(ctx, buf, len, pos);
|
spufs_get_dma_info(ctx, &info);
|
||||||
spin_unlock(&ctx->csa.register_lock);
|
spin_unlock(&ctx->csa.register_lock);
|
||||||
spu_release_saved(ctx);
|
spu_release_saved(ctx);
|
||||||
|
|
||||||
return ret;
|
return simple_read_from_buffer(buf, len, pos, &info,
|
||||||
|
sizeof(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations spufs_dma_info_fops = {
|
static const struct file_operations spufs_dma_info_fops = {
|
||||||
|
@ -2136,13 +2164,31 @@ static const struct file_operations spufs_dma_info_fops = {
|
||||||
.llseek = no_llseek,
|
.llseek = no_llseek,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void spufs_get_proxydma_info(struct spu_context *ctx,
|
||||||
|
struct spu_proxydma_info *info)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
info->proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
|
||||||
|
info->proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
|
||||||
|
info->proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
struct mfc_cq_sr *qp = &info->proxydma_info_command_data[i];
|
||||||
|
struct mfc_cq_sr *puqp = &ctx->csa.priv2.puq[i];
|
||||||
|
|
||||||
|
qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
|
||||||
|
qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
|
||||||
|
qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
|
||||||
|
qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
|
static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
|
||||||
char __user *buf, size_t len, loff_t *pos)
|
char __user *buf, size_t len, loff_t *pos)
|
||||||
{
|
{
|
||||||
struct spu_proxydma_info info;
|
struct spu_proxydma_info info;
|
||||||
struct mfc_cq_sr *qp, *puqp;
|
|
||||||
int ret = sizeof info;
|
int ret = sizeof info;
|
||||||
int i;
|
|
||||||
|
|
||||||
if (len < ret)
|
if (len < ret)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -2150,18 +2196,7 @@ static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
|
||||||
if (!access_ok(buf, len))
|
if (!access_ok(buf, len))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
|
spufs_get_proxydma_info(ctx, &info);
|
||||||
info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
|
|
||||||
info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
|
|
||||||
for (i = 0; i < 8; i++) {
|
|
||||||
qp = &info.proxydma_info_command_data[i];
|
|
||||||
puqp = &ctx->csa.priv2.puq[i];
|
|
||||||
|
|
||||||
qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
|
|
||||||
qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
|
|
||||||
qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
|
|
||||||
qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
|
|
||||||
}
|
|
||||||
|
|
||||||
return simple_read_from_buffer(buf, len, pos, &info,
|
return simple_read_from_buffer(buf, len, pos, &info,
|
||||||
sizeof info);
|
sizeof info);
|
||||||
|
@ -2171,17 +2206,19 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
|
||||||
size_t len, loff_t *pos)
|
size_t len, loff_t *pos)
|
||||||
{
|
{
|
||||||
struct spu_context *ctx = file->private_data;
|
struct spu_context *ctx = file->private_data;
|
||||||
|
struct spu_proxydma_info info;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = spu_acquire_saved(ctx);
|
ret = spu_acquire_saved(ctx);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
spin_lock(&ctx->csa.register_lock);
|
spin_lock(&ctx->csa.register_lock);
|
||||||
ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
|
spufs_get_proxydma_info(ctx, &info);
|
||||||
spin_unlock(&ctx->csa.register_lock);
|
spin_unlock(&ctx->csa.register_lock);
|
||||||
spu_release_saved(ctx);
|
spu_release_saved(ctx);
|
||||||
|
|
||||||
return ret;
|
return simple_read_from_buffer(buf, len, pos, &info,
|
||||||
|
sizeof(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations spufs_proxydma_info_fops = {
|
static const struct file_operations spufs_proxydma_info_fops = {
|
||||||
|
|
Loading…
Add table
Reference in a new issue