Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2015-2018 Etnaviv Project
0004  */
0005 
0006 #include <linux/kernel.h>
0007 
0008 #include "etnaviv_gem.h"
0009 #include "etnaviv_gpu.h"
0010 
0011 #include "cmdstream.xml.h"
0012 
0013 #define EXTRACT(val, field) (((val) & field##__MASK) >> field##__SHIFT)
0014 
0015 struct etna_validation_state {
0016     struct etnaviv_gpu *gpu;
0017     const struct drm_etnaviv_gem_submit_reloc *relocs;
0018     unsigned int num_relocs;
0019     u32 *start;
0020 };
0021 
0022 static const struct {
0023     u16 offset;
0024     u16 size;
0025 } etnaviv_sensitive_states[] __initconst = {
0026 #define ST(start, num) { (start) >> 2, (num) }
0027     /* 2D */
0028     ST(0x1200, 1),
0029     ST(0x1228, 1),
0030     ST(0x1238, 1),
0031     ST(0x1284, 1),
0032     ST(0x128c, 1),
0033     ST(0x1304, 1),
0034     ST(0x1310, 1),
0035     ST(0x1318, 1),
0036     ST(0x12800, 4),
0037     ST(0x128a0, 4),
0038     ST(0x128c0, 4),
0039     ST(0x12970, 4),
0040     ST(0x12a00, 8),
0041     ST(0x12b40, 8),
0042     ST(0x12b80, 8),
0043     ST(0x12ce0, 8),
0044     /* 3D */
0045     ST(0x0644, 1),
0046     ST(0x064c, 1),
0047     ST(0x0680, 8),
0048     ST(0x086c, 1),
0049     ST(0x1028, 1),
0050     ST(0x1410, 1),
0051     ST(0x1430, 1),
0052     ST(0x1458, 1),
0053     ST(0x1460, 8),
0054     ST(0x1480, 8),
0055     ST(0x1500, 8),
0056     ST(0x1520, 8),
0057     ST(0x1608, 1),
0058     ST(0x1610, 1),
0059     ST(0x1658, 1),
0060     ST(0x165c, 1),
0061     ST(0x1664, 1),
0062     ST(0x1668, 1),
0063     ST(0x16a4, 1),
0064     ST(0x16c0, 8),
0065     ST(0x16e0, 8),
0066     ST(0x1740, 8),
0067     ST(0x17c0, 8),
0068     ST(0x17e0, 8),
0069     ST(0x2400, 14 * 16),
0070     ST(0x3824, 1),
0071     ST(0x10800, 32 * 16),
0072     ST(0x14600, 16),
0073     ST(0x14800, 8 * 8),
0074 #undef ST
0075 };
0076 
0077 #define ETNAVIV_STATES_SIZE (VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK + 1u)
0078 static DECLARE_BITMAP(etnaviv_states, ETNAVIV_STATES_SIZE);
0079 
0080 void __init etnaviv_validate_init(void)
0081 {
0082     unsigned int i;
0083 
0084     for (i = 0; i < ARRAY_SIZE(etnaviv_sensitive_states); i++)
0085         bitmap_set(etnaviv_states, etnaviv_sensitive_states[i].offset,
0086                etnaviv_sensitive_states[i].size);
0087 }
0088 
0089 static void etnaviv_warn_if_non_sensitive(struct etna_validation_state *state,
0090     unsigned int buf_offset, unsigned int state_addr)
0091 {
0092     if (state->num_relocs && state->relocs->submit_offset < buf_offset) {
0093         dev_warn_once(state->gpu->dev,
0094                   "%s: relocation for non-sensitive state 0x%x at offset %u\n",
0095                   __func__, state_addr,
0096                   state->relocs->submit_offset);
0097         while (state->num_relocs &&
0098                state->relocs->submit_offset < buf_offset) {
0099             state->relocs++;
0100             state->num_relocs--;
0101         }
0102     }
0103 }
0104 
0105 static bool etnaviv_validate_load_state(struct etna_validation_state *state,
0106     u32 *ptr, unsigned int state_offset, unsigned int num)
0107 {
0108     unsigned int size = min(ETNAVIV_STATES_SIZE, state_offset + num);
0109     unsigned int st_offset = state_offset, buf_offset;
0110 
0111     for_each_set_bit_from(st_offset, etnaviv_states, size) {
0112         buf_offset = (ptr - state->start +
0113                   st_offset - state_offset) * 4;
0114 
0115         etnaviv_warn_if_non_sensitive(state, buf_offset, st_offset * 4);
0116         if (state->num_relocs &&
0117             state->relocs->submit_offset == buf_offset) {
0118             state->relocs++;
0119             state->num_relocs--;
0120             continue;
0121         }
0122 
0123         dev_warn_ratelimited(state->gpu->dev,
0124                      "%s: load state touches restricted state 0x%x at offset %u\n",
0125                      __func__, st_offset * 4, buf_offset);
0126         return false;
0127     }
0128 
0129     if (state->num_relocs) {
0130         buf_offset = (ptr - state->start + num) * 4;
0131         etnaviv_warn_if_non_sensitive(state, buf_offset, st_offset * 4 +
0132                           state->relocs->submit_offset -
0133                           buf_offset);
0134     }
0135 
0136     return true;
0137 }
0138 
0139 static uint8_t cmd_length[32] = {
0140     [FE_OPCODE_DRAW_PRIMITIVES] = 4,
0141     [FE_OPCODE_DRAW_INDEXED_PRIMITIVES] = 6,
0142     [FE_OPCODE_DRAW_INSTANCED] = 4,
0143     [FE_OPCODE_NOP] = 2,
0144     [FE_OPCODE_STALL] = 2,
0145 };
0146 
0147 bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu, u32 *stream,
0148                   unsigned int size,
0149                   struct drm_etnaviv_gem_submit_reloc *relocs,
0150                   unsigned int reloc_size)
0151 {
0152     struct etna_validation_state state;
0153     u32 *buf = stream;
0154     u32 *end = buf + size;
0155 
0156     state.gpu = gpu;
0157     state.relocs = relocs;
0158     state.num_relocs = reloc_size;
0159     state.start = stream;
0160 
0161     while (buf < end) {
0162         u32 cmd = *buf;
0163         unsigned int len, n, off;
0164         unsigned int op = cmd >> 27;
0165 
0166         switch (op) {
0167         case FE_OPCODE_LOAD_STATE:
0168             n = EXTRACT(cmd, VIV_FE_LOAD_STATE_HEADER_COUNT);
0169             len = ALIGN(1 + n, 2);
0170             if (buf + len > end)
0171                 break;
0172 
0173             off = EXTRACT(cmd, VIV_FE_LOAD_STATE_HEADER_OFFSET);
0174             if (!etnaviv_validate_load_state(&state, buf + 1,
0175                              off, n))
0176                 return false;
0177             break;
0178 
0179         case FE_OPCODE_DRAW_2D:
0180             n = EXTRACT(cmd, VIV_FE_DRAW_2D_HEADER_COUNT);
0181             if (n == 0)
0182                 n = 256;
0183             len = 2 + n * 2;
0184             break;
0185 
0186         default:
0187             len = cmd_length[op];
0188             if (len == 0) {
0189                 dev_err(gpu->dev, "%s: op %u not permitted at offset %tu\n",
0190                     __func__, op, buf - state.start);
0191                 return false;
0192             }
0193             break;
0194         }
0195 
0196         buf += len;
0197     }
0198 
0199     if (buf > end) {
0200         dev_err(gpu->dev, "%s: commands overflow end of buffer: %tu > %u\n",
0201             __func__, buf - state.start, size);
0202         return false;
0203     }
0204 
0205     return true;
0206 }