drm/radeon/kms/atom: fix handling of FB scratch indices
authorAlex Deucher <alexander.deucher@amd.com>
Wed, 19 Oct 2011 00:10:05 +0000 (20:10 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 25 Oct 2011 05:10:14 +0000 (07:10 +0200)
commit 5a6e8482a16e61250a9121fc9ec719ab0529e760 upstream.

FB scratch indices are dword indices, but we were treating
them as byte indices.  As such, we were getting the wrong
FB scratch data for non-0 indices.  Fix the indices and
guard the indexing against indices larger than the scratch
allocation.

Fixes memory corruption on some boards if data was written
past the end of the FB scratch array.

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Reported-by: Dave Airlie <airlied@redhat.com>
Tested-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/gpu/drm/radeon/atom.c
drivers/gpu/drm/radeon/atom.h

index ebdb0fdb8348ad7b217e3d46027207789e0ad67f..9a0aee2f06504a7ea2de039238407e10976e2429 100644 (file)
@@ -277,7 +277,12 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
        case ATOM_ARG_FB:
                idx = U8(*ptr);
                (*ptr)++;
-               val = gctx->scratch[((gctx->fb_base + idx) / 4)];
+               if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
+                       DRM_ERROR("ATOM: fb read beyond scratch region: %d vs. %d\n",
+                                 gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
+                       val = 0;
+               } else
+                       val = gctx->scratch[(gctx->fb_base / 4) + idx];
                if (print)
                        DEBUG("FB[0x%02X]", idx);
                break;
@@ -531,7 +536,11 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
        case ATOM_ARG_FB:
                idx = U8(*ptr);
                (*ptr)++;
-               gctx->scratch[((gctx->fb_base + idx) / 4)] = val;
+               if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) {
+                       DRM_ERROR("ATOM: fb write beyond scratch region: %d vs. %d\n",
+                                 gctx->fb_base + (idx * 4), gctx->scratch_size_bytes);
+               } else
+                       gctx->scratch[(gctx->fb_base / 4) + idx] = val;
                DEBUG("FB[0x%02X]", idx);
                break;
        case ATOM_ARG_PLL:
@@ -1367,11 +1376,13 @@ int atom_allocate_fb_scratch(struct atom_context *ctx)
 
                usage_bytes = firmware_usage->asFirmwareVramReserveInfo[0].usFirmwareUseInKb * 1024;
        }
+       ctx->scratch_size_bytes = 0;
        if (usage_bytes == 0)
                usage_bytes = 20 * 1024;
        /* allocate some scratch memory */
        ctx->scratch = kzalloc(usage_bytes, GFP_KERNEL);
        if (!ctx->scratch)
                return -ENOMEM;
+       ctx->scratch_size_bytes = usage_bytes;
        return 0;
 }
index a589a55b223e660576a9e393be36c371ed7f2f71..93cfe2086ba023b82b4271b136730a2d3a4cd25d 100644 (file)
@@ -137,6 +137,7 @@ struct atom_context {
        int cs_equal, cs_above;
        int io_mode;
        uint32_t *scratch;
+       int scratch_size_bytes;
 };
 
 extern int atom_debug;