[POWERPC] spufs: Use SPU master control to prevent wild SPU execution
authorArnd Bergmann <arnd@arndb.de>
Mon, 20 Nov 2006 17:45:08 +0000 (18:45 +0100)
committerPaul Mackerras <paulus@samba.org>
Mon, 4 Dec 2006 09:40:02 +0000 (20:40 +1100)
When the user changes the runcontrol register, an SPU might be
running without a process being attached to it and waiting for
events. In order to prevent this, make sure we always disable
the priv1 master control when we're not inside of spu_run.

Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/platforms/cell/spufs/backing_ops.c
arch/powerpc/platforms/cell/spufs/context.c
arch/powerpc/platforms/cell/spufs/hw_ops.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/cell/spufs/run.c
arch/powerpc/platforms/cell/spufs/spufs.h

index 21b28f6..4a8e998 100644 (file)
@@ -280,9 +280,26 @@ static void spu_backing_runcntl_write(struct spu_context *ctx, u32 val)
        spin_unlock(&ctx->csa.register_lock);
 }
 
-static void spu_backing_runcntl_stop(struct spu_context *ctx)
+static void spu_backing_master_start(struct spu_context *ctx)
 {
-       spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP);
+       struct spu_state *csa = &ctx->csa;
+       u64 sr1;
+
+       spin_lock(&csa->register_lock);
+       sr1 = csa->priv1.mfc_sr1_RW | MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+       csa->priv1.mfc_sr1_RW = sr1;
+       spin_unlock(&csa->register_lock);
+}
+
+static void spu_backing_master_stop(struct spu_context *ctx)
+{
+       struct spu_state *csa = &ctx->csa;
+       u64 sr1;
+
+       spin_lock(&csa->register_lock);
+       sr1 = csa->priv1.mfc_sr1_RW & ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+       csa->priv1.mfc_sr1_RW = sr1;
+       spin_unlock(&csa->register_lock);
 }
 
 static int spu_backing_set_mfc_query(struct spu_context * ctx, u32 mask,
@@ -347,7 +364,8 @@ struct spu_context_ops spu_backing_ops = {
        .status_read = spu_backing_status_read,
        .get_ls = spu_backing_get_ls,
        .runcntl_write = spu_backing_runcntl_write,
-       .runcntl_stop = spu_backing_runcntl_stop,
+       .master_start = spu_backing_master_start,
+       .master_stop = spu_backing_master_stop,
        .set_mfc_query = spu_backing_set_mfc_query,
        .read_mfc_tagstatus = spu_backing_read_mfc_tagstatus,
        .get_mfc_free_elements = spu_backing_get_mfc_free_elements,
index 48eb050..0870009 100644 (file)
@@ -122,29 +122,29 @@ void spu_unmap_mappings(struct spu_context *ctx)
 
 int spu_acquire_exclusive(struct spu_context *ctx)
 {
-       int ret = 0;
-
-       down_write(&ctx->state_sema);
-       /* ctx is about to be freed, can't acquire any more */
-       if (!ctx->owner) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (ctx->state == SPU_STATE_SAVED) {
-               ret = spu_activate(ctx, 0);
-               if (ret)
-                       goto out;
-               ctx->state = SPU_STATE_RUNNABLE;
-       } else {
-               /* We need to exclude userspace access to the context. */
-               spu_unmap_mappings(ctx);
-       }
+       int ret = 0;
+
+       down_write(&ctx->state_sema);
+       /* ctx is about to be freed, can't acquire any more */
+       if (!ctx->owner) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (ctx->state == SPU_STATE_SAVED) {
+               ret = spu_activate(ctx, 0);
+               if (ret)
+                       goto out;
+               ctx->state = SPU_STATE_RUNNABLE;
+       } else {
+               /* We need to exclude userspace access to the context. */
+               spu_unmap_mappings(ctx);
+       }
 
 out:
-       if (ret)
-               up_write(&ctx->state_sema);
-       return ret;
+       if (ret)
+               up_write(&ctx->state_sema);
+       return ret;
 }
 
 int spu_acquire_runnable(struct spu_context *ctx)
index 79c304e..69fc342 100644 (file)
@@ -216,13 +216,26 @@ static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val)
        spin_unlock_irq(&ctx->spu->register_lock);
 }
 
-static void spu_hw_runcntl_stop(struct spu_context *ctx)
+static void spu_hw_master_start(struct spu_context *ctx)
 {
-       spin_lock_irq(&ctx->spu->register_lock);
-       out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP);
-       while (in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING)
-               cpu_relax();
-       spin_unlock_irq(&ctx->spu->register_lock);
+       struct spu *spu = ctx->spu;
+       u64 sr1;
+
+       spin_lock_irq(&spu->register_lock);
+       sr1 = spu_mfc_sr1_get(spu) | MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+       spu_mfc_sr1_set(spu, sr1);
+       spin_unlock_irq(&spu->register_lock);
+}
+
+static void spu_hw_master_stop(struct spu_context *ctx)
+{
+       struct spu *spu = ctx->spu;
+       u64 sr1;
+
+       spin_lock_irq(&spu->register_lock);
+       sr1 = spu_mfc_sr1_get(spu) & ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+       spu_mfc_sr1_set(spu, sr1);
+       spin_unlock_irq(&spu->register_lock);
 }
 
 static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode)
@@ -295,7 +308,8 @@ struct spu_context_ops spu_hw_ops = {
        .status_read = spu_hw_status_read,
        .get_ls = spu_hw_get_ls,
        .runcntl_write = spu_hw_runcntl_write,
-       .runcntl_stop = spu_hw_runcntl_stop,
+       .master_start = spu_hw_master_start,
+       .master_stop = spu_hw_master_stop,
        .set_mfc_query = spu_hw_set_mfc_query,
        .read_mfc_tagstatus = spu_hw_read_mfc_tagstatus,
        .get_mfc_free_elements = spu_hw_get_mfc_free_elements,
index 9e457be..1fbcc53 100644 (file)
@@ -248,8 +248,13 @@ static int spu_setup_isolated(struct spu_context *ctx)
        if (!isolated_loader)
                return -ENODEV;
 
-       if ((ret = spu_acquire_exclusive(ctx)) != 0)
-               return ret;
+       /* prevent concurrent operation with spu_run */
+       down(&ctx->run_sema);
+       ctx->ops->master_start(ctx);
+
+       ret = spu_acquire_exclusive(ctx);
+       if (ret)
+               goto out;
 
        mfc_cntl = &ctx->spu->priv2->mfc_control_RW;
 
@@ -315,12 +320,14 @@ out_drop_priv:
 
 out_unlock:
        spu_release_exclusive(ctx);
+out:
+       ctx->ops->master_stop(ctx);
+       up(&ctx->run_sema);
        return ret;
 }
 
 int spu_recycle_isolated(struct spu_context *ctx)
 {
-       ctx->ops->runcntl_stop(ctx);
        return spu_setup_isolated(ctx);
 }
 
@@ -435,6 +442,8 @@ out:
        if (ret >= 0 && (flags & SPU_CREATE_ISOLATE)) {
                int setup_err = spu_setup_isolated(
                                SPUFS_I(dentry->d_inode)->i_ctx);
+               /* FIXME: clean up context again on failure to avoid
+                         leak. */
                if (setup_err)
                        ret = setup_err;
        }
index c88fd7f..212b9c2 100644 (file)
@@ -207,6 +207,7 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
        if (down_interruptible(&ctx->run_sema))
                return -ERESTARTSYS;
 
+       ctx->ops->master_start(ctx);
        ctx->event_return = 0;
        ret = spu_run_init(ctx, npc);
        if (ret)
@@ -234,7 +235,7 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
        } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP |
                                      SPU_STATUS_STOPPED_BY_HALT)));
 
-       ctx->ops->runcntl_stop(ctx);
+       ctx->ops->master_stop(ctx);
        ret = spu_run_fini(ctx, npc, &status);
        spu_yield(ctx);
 
index 3e7cfc2..135fbb5 100644 (file)
@@ -116,7 +116,8 @@ struct spu_context_ops {
         u32(*status_read) (struct spu_context * ctx);
        char*(*get_ls) (struct spu_context * ctx);
        void (*runcntl_write) (struct spu_context * ctx, u32 data);
-       void (*runcntl_stop) (struct spu_context * ctx);
+       void (*master_start) (struct spu_context * ctx);
+       void (*master_stop) (struct spu_context * ctx);
        int (*set_mfc_query)(struct spu_context * ctx, u32 mask, u32 mode);
        u32 (*read_mfc_tagstatus)(struct spu_context * ctx);
        u32 (*get_mfc_free_elements)(struct spu_context *ctx);