diff options
-rw-r--r-- | drivers/gpu/drm/i915/i915_cmd_parser.c | 74 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 5 |
2 files changed, 48 insertions, 31 deletions
diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 9605ff8f2fcd..5fc49bbcdb9d 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c | |||
@@ -123,7 +123,7 @@ static const struct drm_i915_cmd_descriptor common_cmds[] = { | |||
123 | CMD( MI_SEMAPHORE_MBOX, SMI, !F, 0xFF, R ), | 123 | CMD( MI_SEMAPHORE_MBOX, SMI, !F, 0xFF, R ), |
124 | CMD( MI_STORE_DWORD_INDEX, SMI, !F, 0xFF, R ), | 124 | CMD( MI_STORE_DWORD_INDEX, SMI, !F, 0xFF, R ), |
125 | CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, W, | 125 | CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, W, |
126 | .reg = { .offset = 1, .mask = 0x007FFFFC } ), | 126 | .reg = { .offset = 1, .mask = 0x007FFFFC, .step = 2 } ), |
127 | CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, W | B, | 127 | CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, W | B, |
128 | .reg = { .offset = 1, .mask = 0x007FFFFC }, | 128 | .reg = { .offset = 1, .mask = 0x007FFFFC }, |
129 | .bits = {{ | 129 | .bits = {{ |
@@ -934,7 +934,7 @@ bool i915_needs_cmd_parser(struct intel_engine_cs *ring) | |||
934 | 934 | ||
935 | static bool check_cmd(const struct intel_engine_cs *ring, | 935 | static bool check_cmd(const struct intel_engine_cs *ring, |
936 | const struct drm_i915_cmd_descriptor *desc, | 936 | const struct drm_i915_cmd_descriptor *desc, |
937 | const u32 *cmd, | 937 | const u32 *cmd, u32 length, |
938 | const bool is_master, | 938 | const bool is_master, |
939 | bool *oacontrol_set) | 939 | bool *oacontrol_set) |
940 | { | 940 | { |
@@ -950,38 +950,49 @@ static bool check_cmd(const struct intel_engine_cs *ring, | |||
950 | } | 950 | } |
951 | 951 | ||
952 | if (desc->flags & CMD_DESC_REGISTER) { | 952 | if (desc->flags & CMD_DESC_REGISTER) { |
953 | u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask; | ||
954 | |||
955 | /* | 953 | /* |
956 | * OACONTROL requires some special handling for writes. We | 954 | * Get the distance between individual register offset |
957 | * want to make sure that any batch which enables OA also | 955 | * fields if the command can perform more than one |
958 | * disables it before the end of the batch. The goal is to | 956 | * access at a time. |
959 | * prevent one process from snooping on the perf data from | ||
960 | * another process. To do that, we need to check the value | ||
961 | * that will be written to the register. Hence, limit | ||
962 | * OACONTROL writes to only MI_LOAD_REGISTER_IMM commands. | ||
963 | */ | 957 | */ |
964 | if (reg_addr == OACONTROL) { | 958 | const u32 step = desc->reg.step ? desc->reg.step : length; |
965 | if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { | 959 | u32 offset; |
966 | DRM_DEBUG_DRIVER("CMD: Rejected LRM to OACONTROL\n"); | 960 | |
967 | return false; | 961 | for (offset = desc->reg.offset; offset < length; |
962 | offset += step) { | ||
963 | const u32 reg_addr = cmd[offset] & desc->reg.mask; | ||
964 | |||
965 | /* | ||
966 | * OACONTROL requires some special handling for | ||
967 | * writes. We want to make sure that any batch which | ||
968 | * enables OA also disables it before the end of the | ||
969 | * batch. The goal is to prevent one process from | ||
970 | * snooping on the perf data from another process. To do | ||
971 | * that, we need to check the value that will be written | ||
972 | * to the register. Hence, limit OACONTROL writes to | ||
973 | * only MI_LOAD_REGISTER_IMM commands. | ||
974 | */ | ||
975 | if (reg_addr == OACONTROL) { | ||
976 | if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { | ||
977 | DRM_DEBUG_DRIVER("CMD: Rejected LRM to OACONTROL\n"); | ||
978 | return false; | ||
979 | } | ||
980 | |||
981 | if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1)) | ||
982 | *oacontrol_set = (cmd[offset + 1] != 0); | ||
968 | } | 983 | } |
969 | 984 | ||
970 | if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1)) | 985 | if (!valid_reg(ring->reg_table, |
971 | *oacontrol_set = (cmd[2] != 0); | 986 | ring->reg_count, reg_addr)) { |
972 | } | 987 | if (!is_master || |
973 | 988 | !valid_reg(ring->master_reg_table, | |
974 | if (!valid_reg(ring->reg_table, | 989 | ring->master_reg_count, |
975 | ring->reg_count, reg_addr)) { | 990 | reg_addr)) { |
976 | if (!is_master || | 991 | DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", |
977 | !valid_reg(ring->master_reg_table, | 992 | reg_addr, *cmd, |
978 | ring->master_reg_count, | 993 | ring->id); |
979 | reg_addr)) { | 994 | return false; |
980 | DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", | 995 | } |
981 | reg_addr, | ||
982 | *cmd, | ||
983 | ring->id); | ||
984 | return false; | ||
985 | } | 996 | } |
986 | } | 997 | } |
987 | } | 998 | } |
@@ -1105,7 +1116,8 @@ int i915_parse_cmds(struct intel_engine_cs *ring, | |||
1105 | break; | 1116 | break; |
1106 | } | 1117 | } |
1107 | 1118 | ||
1108 | if (!check_cmd(ring, desc, cmd, is_master, &oacontrol_set)) { | 1119 | if (!check_cmd(ring, desc, cmd, length, is_master, |
1120 | &oacontrol_set)) { | ||
1109 | ret = -EINVAL; | 1121 | ret = -EINVAL; |
1110 | break; | 1122 | break; |
1111 | } | 1123 | } |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 72f5a3f9dbf2..542fac628b28 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -2300,10 +2300,15 @@ struct drm_i915_cmd_descriptor { | |||
2300 | * Describes where to find a register address in the command to check | 2300 | * Describes where to find a register address in the command to check |
2301 | * against the ring's register whitelist. Only valid if flags has the | 2301 | * against the ring's register whitelist. Only valid if flags has the |
2302 | * CMD_DESC_REGISTER bit set. | 2302 | * CMD_DESC_REGISTER bit set. |
2303 | * | ||
2304 | * A non-zero step value implies that the command may access multiple | ||
2305 | * registers in sequence (e.g. LRI), in that case step gives the | ||
2306 | * distance in dwords between individual offset fields. | ||
2303 | */ | 2307 | */ |
2304 | struct { | 2308 | struct { |
2305 | u32 offset; | 2309 | u32 offset; |
2306 | u32 mask; | 2310 | u32 mask; |
2311 | u32 step; | ||
2307 | } reg; | 2312 | } reg; |
2308 | 2313 | ||
2309 | #define MAX_CMD_DESC_BITMASKS 3 | 2314 | #define MAX_CMD_DESC_BITMASKS 3 |