diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/atom.c')
-rw-r--r-- | drivers/gpu/drm/radeon/atom.c | 47 |
1 files changed, 33 insertions, 14 deletions
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index ceb6d772ef..5bc3e6b41c 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -60,6 +60,7 @@ typedef struct { struct atom_context *ctx; uint32_t *ps, *ws; + int ps_size, ws_size; int ps_shift; uint16_t start; unsigned last_jump; @@ -68,8 +69,8 @@ typedef struct { } atom_exec_context; int atom_debug = 0; -static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params); -int atom_execute_table(struct atom_context *ctx, int index, uint32_t *params); +static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params, int params_size); +int atom_execute_table(struct atom_context *ctx, int index, uint32_t *params, int params_size); static uint32_t atom_arg_mask[8] = { 0xFFFFFFFF, 0x0000FFFF, 0x00FFFF00, 0xFFFF0000, @@ -221,7 +222,10 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, (*ptr)++; /* get_unaligned_le32 avoids unaligned accesses from atombios * tables, noticed on a DEC Alpha. */ - val = get_unaligned_le32((u32 *)&ctx->ps[idx]); + if (idx < ctx->ps_size) + val = get_unaligned_le32((u32 *)&ctx->ps[idx]); + else + pr_info("PS index out of range: %i > %i\n", idx, ctx->ps_size); if (print) DEBUG("PS[0x%02X,0x%04X]", idx, val); break; @@ -259,7 +263,10 @@ static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, val = gctx->reg_block; break; default: - val = ctx->ws[idx]; + if (idx < ctx->ws_size) + val = ctx->ws[idx]; + else + pr_info("WS index out of range: %i > %i\n", idx, ctx->ws_size); } break; case ATOM_ARG_ID: @@ -494,6 +501,10 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, idx = U8(*ptr); (*ptr)++; DEBUG("PS[0x%02X]", idx); + if (idx >= ctx->ps_size) { + pr_info("PS index out of range: %i > %i\n", idx, ctx->ps_size); + return; + } ctx->ps[idx] = cpu_to_le32(val); break; case ATOM_ARG_WS: @@ -526,6 +537,10 @@ static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr, gctx->reg_block = val; break; default: + if (idx >= ctx->ws_size) { + pr_info("WS index out of range: %i > %i\n", idx, ctx->ws_size); + return; + } ctx->ws[idx] = val; } break; @@ -623,7 +638,7 @@ static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg) else SDEBUG(" table: %d\n", idx); if (U16(ctx->ctx->cmd_table + 4 + 2 * idx)) - r = atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift); + r = atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift, ctx->ps_size - ctx->ps_shift); if (r) { ctx->abort = true; } @@ -1152,7 +1167,7 @@ static struct { atom_op_shr, ATOM_ARG_MC}, { atom_op_debug, 0},}; -static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params) +static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32_t *params, int params_size) { int base = CU16(ctx->cmd_table + 4 + 2 * index); int len, ws, ps, ptr; @@ -1174,12 +1189,16 @@ static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32 ectx.ps_shift = ps / 4; ectx.start = base; ectx.ps = params; + ectx.ps_size = params_size; ectx.abort = false; ectx.last_jump = 0; - if (ws) + if (ws) { ectx.ws = kcalloc(4, ws, GFP_KERNEL); - else + ectx.ws_size = ws; + } else { ectx.ws = NULL; + ectx.ws_size = 0; + } debug_depth++; while (1) { @@ -1212,7 +1231,7 @@ free: return ret; } -int atom_execute_table_scratch_unlocked(struct atom_context *ctx, int index, uint32_t *params) +int atom_execute_table_scratch_unlocked(struct atom_context *ctx, int index, uint32_t *params, int params_size) { int r; @@ -1228,16 +1247,16 @@ int atom_execute_table_scratch_unlocked(struct atom_context *ctx, int index, uin /* reset divmul */ ctx->divmul[0] = 0; ctx->divmul[1] = 0; - r = atom_execute_table_locked(ctx, index, params); + r = atom_execute_table_locked(ctx, index, params, params_size); mutex_unlock(&ctx->mutex); return r; } -int atom_execute_table(struct atom_context *ctx, int index, uint32_t *params) +int atom_execute_table(struct atom_context *ctx, int index, uint32_t *params, int params_size) { int r; mutex_lock(&ctx->scratch_mutex); - r = atom_execute_table_scratch_unlocked(ctx, index, params); + r = atom_execute_table_scratch_unlocked(ctx, index, params, params_size); mutex_unlock(&ctx->scratch_mutex); return r; } @@ -1335,7 +1354,7 @@ int atom_asic_init(struct atom_context *ctx) if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT)) return 1; - ret = atom_execute_table(ctx, ATOM_CMD_INIT, ps); + ret = atom_execute_table(ctx, ATOM_CMD_INIT, ps, 16); if (ret) return ret; @@ -1343,7 +1362,7 @@ int atom_asic_init(struct atom_context *ctx) if (rdev->family < CHIP_R600) { if (CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_SPDFANCNTL)) - atom_execute_table(ctx, ATOM_CMD_SPDFANCNTL, ps); + atom_execute_table(ctx, ATOM_CMD_SPDFANCNTL, ps, 16); } return ret; } |