1 /* 2 * SPDX-License-Identifier: MIT 3 * 4 * Copyright © 2018 Intel Corporation 5 */ 6 7 #include <linux/nospec.h> 8 9 #include "i915_drv.h" 10 #include "i915_query.h" 11 #include <uapi/drm/i915_drm.h> 12 13 static int copy_query_item(void *query_hdr, size_t query_sz, 14 u32 total_length, 15 struct drm_i915_query_item *query_item) 16 { 17 if (query_item->length == 0) 18 return total_length; 19 20 if (query_item->length < total_length) 21 return -EINVAL; 22 23 if (copy_from_user(query_hdr, u64_to_user_ptr(query_item->data_ptr), 24 query_sz)) 25 return -EFAULT; 26 27 if (!access_ok(u64_to_user_ptr(query_item->data_ptr), 28 total_length)) 29 return -EFAULT; 30 31 return 0; 32 } 33 34 static int query_topology_info(struct drm_i915_private *dev_priv, 35 struct drm_i915_query_item *query_item) 36 { 37 const struct sseu_dev_info *sseu = &RUNTIME_INFO(dev_priv)->sseu; 38 struct drm_i915_query_topology_info topo; 39 u32 slice_length, subslice_length, eu_length, total_length; 40 u8 subslice_stride = GEN_SSEU_STRIDE(sseu->max_subslices); 41 u8 eu_stride = GEN_SSEU_STRIDE(sseu->max_eus_per_subslice); 42 int ret; 43 44 if (query_item->flags != 0) 45 return -EINVAL; 46 47 if (sseu->max_slices == 0) 48 return -ENODEV; 49 50 BUILD_BUG_ON(sizeof(u8) != sizeof(sseu->slice_mask)); 51 52 slice_length = sizeof(sseu->slice_mask); 53 subslice_length = sseu->max_slices * subslice_stride; 54 eu_length = sseu->max_slices * sseu->max_subslices * eu_stride; 55 total_length = sizeof(topo) + slice_length + subslice_length + 56 eu_length; 57 58 ret = copy_query_item(&topo, sizeof(topo), total_length, 59 query_item); 60 if (ret != 0) 61 return ret; 62 63 if (topo.flags != 0) 64 return -EINVAL; 65 66 memset(&topo, 0, sizeof(topo)); 67 topo.max_slices = sseu->max_slices; 68 topo.max_subslices = sseu->max_subslices; 69 topo.max_eus_per_subslice = sseu->max_eus_per_subslice; 70 71 topo.subslice_offset = slice_length; 72 topo.subslice_stride = subslice_stride; 73 topo.eu_offset = slice_length + subslice_length; 74 topo.eu_stride = eu_stride; 75 76 if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr), 77 &topo, sizeof(topo))) 78 return -EFAULT; 79 80 if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr + sizeof(topo)), 81 &sseu->slice_mask, slice_length)) 82 return -EFAULT; 83 84 if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr + 85 sizeof(topo) + slice_length), 86 sseu->subslice_mask, subslice_length)) 87 return -EFAULT; 88 89 if (__copy_to_user(u64_to_user_ptr(query_item->data_ptr + 90 sizeof(topo) + 91 slice_length + subslice_length), 92 sseu->eu_mask, eu_length)) 93 return -EFAULT; 94 95 return total_length; 96 } 97 98 static int 99 query_engine_info(struct drm_i915_private *i915, 100 struct drm_i915_query_item *query_item) 101 { 102 struct drm_i915_query_engine_info __user *query_ptr = 103 u64_to_user_ptr(query_item->data_ptr); 104 struct drm_i915_engine_info __user *info_ptr; 105 struct drm_i915_query_engine_info query; 106 struct drm_i915_engine_info info = { }; 107 struct intel_engine_cs *engine; 108 int len, ret; 109 110 if (query_item->flags) 111 return -EINVAL; 112 113 len = sizeof(struct drm_i915_query_engine_info) + 114 RUNTIME_INFO(i915)->num_engines * 115 sizeof(struct drm_i915_engine_info); 116 117 ret = copy_query_item(&query, sizeof(query), len, query_item); 118 if (ret != 0) 119 return ret; 120 121 if (query.num_engines || query.rsvd[0] || query.rsvd[1] || 122 query.rsvd[2]) 123 return -EINVAL; 124 125 info_ptr = &query_ptr->engines[0]; 126 127 for_each_uabi_engine(engine, i915) { 128 info.engine.engine_class = engine->uabi_class; 129 info.engine.engine_instance = engine->uabi_instance; 130 info.capabilities = engine->uabi_capabilities; 131 132 if (__copy_to_user(info_ptr, &info, sizeof(info))) 133 return -EFAULT; 134 135 query.num_engines++; 136 info_ptr++; 137 } 138 139 if (__copy_to_user(query_ptr, &query, sizeof(query))) 140 return -EFAULT; 141 142 return len; 143 } 144 145 static int (* const i915_query_funcs[])(struct drm_i915_private *dev_priv, 146 struct drm_i915_query_item *query_item) = { 147 query_topology_info, 148 query_engine_info, 149 }; 150 151 int i915_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file) 152 { 153 struct drm_i915_private *dev_priv = to_i915(dev); 154 struct drm_i915_query *args = data; 155 struct drm_i915_query_item __user *user_item_ptr = 156 u64_to_user_ptr(args->items_ptr); 157 u32 i; 158 159 if (args->flags != 0) 160 return -EINVAL; 161 162 for (i = 0; i < args->num_items; i++, user_item_ptr++) { 163 struct drm_i915_query_item item; 164 unsigned long func_idx; 165 int ret; 166 167 if (copy_from_user(&item, user_item_ptr, sizeof(item))) 168 return -EFAULT; 169 170 if (item.query_id == 0) 171 return -EINVAL; 172 173 if (overflows_type(item.query_id - 1, unsigned long)) 174 return -EINVAL; 175 176 func_idx = item.query_id - 1; 177 178 ret = -EINVAL; 179 if (func_idx < ARRAY_SIZE(i915_query_funcs)) { 180 func_idx = array_index_nospec(func_idx, 181 ARRAY_SIZE(i915_query_funcs)); 182 ret = i915_query_funcs[func_idx](dev_priv, &item); 183 } 184 185 /* Only write the length back to userspace if they differ. */ 186 if (ret != item.length && put_user(ret, &user_item_ptr->length)) 187 return -EFAULT; 188 } 189 190 return 0; 191 } 192