aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2014-08-09 14:10:24 -0400
committerBen Skeggs <bskeggs@redhat.com>2014-08-09 15:13:25 -0400
commit96af8222cef78ab4d92186d5e10880dc78395415 (patch)
treeb90b8fe780d6e0530dfd98a798a08133ced8823c
parent4acfd707e28c820ba8ed8c12b497413a133d8c8f (diff)
drm/nouveau/pm: audit and version NVIF_PERFMON class and methods
The full object interfaces are about to be exposed to userspace, so we need to check for any security-related issues and version the structs to make it easier to handle any changes we may need in the future. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/perfmon/base.c127
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/class.h31
-rw-r--r--drivers/gpu/drm/nouveau/nvif/class.h34
-rw-r--r--drivers/gpu/drm/nouveau/nvif/ioctl.h2
4 files changed, 116 insertions, 78 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c
index 748100307bb6..63013812f7c9 100644
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c
+++ b/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c
@@ -22,8 +22,11 @@
22 * Authors: Ben Skeggs 22 * Authors: Ben Skeggs
23 */ 23 */
24 24
25#include <core/client.h>
25#include <core/option.h> 26#include <core/option.h>
26#include <core/class.h> 27#include <nvif/unpack.h>
28#include <nvif/class.h>
29#include <nvif/ioctl.h>
27 30
28#include <subdev/clock.h> 31#include <subdev/clock.h>
29 32
@@ -101,24 +104,28 @@ nouveau_perfsig_wrap(struct nouveau_perfmon *ppm, const char *name,
101 * Perfmon object classes 104 * Perfmon object classes
102 ******************************************************************************/ 105 ******************************************************************************/
103static int 106static int
104nouveau_perfctr_query(struct nouveau_object *object, u32 mthd, 107nouveau_perfctr_query(struct nouveau_object *object, void *data, u32 size)
105 void *data, u32 size)
106{ 108{
109 union {
110 struct nvif_perfctr_query_v0 v0;
111 } *args = data;
107 struct nouveau_device *device = nv_device(object); 112 struct nouveau_device *device = nv_device(object);
108 struct nouveau_perfmon *ppm = (void *)object->engine; 113 struct nouveau_perfmon *ppm = (void *)object->engine;
109 struct nouveau_perfdom *dom = NULL, *chk; 114 struct nouveau_perfdom *dom = NULL, *chk;
110 struct nv_perfctr_query *args = data;
111 const bool all = nouveau_boolopt(device->cfgopt, "NvPmShowAll", false); 115 const bool all = nouveau_boolopt(device->cfgopt, "NvPmShowAll", false);
112 const bool raw = nouveau_boolopt(device->cfgopt, "NvPmUnnamed", all); 116 const bool raw = nouveau_boolopt(device->cfgopt, "NvPmUnnamed", all);
113 const char *name; 117 const char *name;
114 int tmp = 0, di, si; 118 int tmp = 0, di, si;
115 char path[64]; 119 int ret;
116
117 if (size < sizeof(*args))
118 return -EINVAL;
119 120
120 di = (args->iter & 0xff000000) >> 24; 121 nv_ioctl(object, "perfctr query size %d\n", size);
121 si = (args->iter & 0x00ffffff) - 1; 122 if (nvif_unpack(args->v0, 0, 0, false)) {
123 nv_ioctl(object, "perfctr query vers %d iter %08x\n",
124 args->v0.version, args->v0.iter);
125 di = (args->v0.iter & 0xff000000) >> 24;
126 si = (args->v0.iter & 0x00ffffff) - 1;
127 } else
128 return ret;
122 129
123 list_for_each_entry(chk, &ppm->domains, head) { 130 list_for_each_entry(chk, &ppm->domains, head) {
124 if (tmp++ == di) { 131 if (tmp++ == di) {
@@ -132,19 +139,17 @@ nouveau_perfctr_query(struct nouveau_object *object, u32 mthd,
132 139
133 if (si >= 0) { 140 if (si >= 0) {
134 if (raw || !(name = dom->signal[si].name)) { 141 if (raw || !(name = dom->signal[si].name)) {
135 snprintf(path, sizeof(path), "/%s/%02x", dom->name, si); 142 snprintf(args->v0.name, sizeof(args->v0.name),
136 name = path; 143 "/%s/%02x", dom->name, si);
144 } else {
145 strncpy(args->v0.name, name, sizeof(args->v0.name));
137 } 146 }
138
139 if (args->name)
140 strncpy(args->name, name, args->size);
141 args->size = strlen(name) + 1;
142 } 147 }
143 148
144 do { 149 do {
145 while (++si < dom->signal_nr) { 150 while (++si < dom->signal_nr) {
146 if (all || dom->signal[si].name) { 151 if (all || dom->signal[si].name) {
147 args->iter = (di << 24) | ++si; 152 args->v0.iter = (di << 24) | ++si;
148 return 0; 153 return 0;
149 } 154 }
150 } 155 }
@@ -153,21 +158,26 @@ nouveau_perfctr_query(struct nouveau_object *object, u32 mthd,
153 dom = list_entry(dom->head.next, typeof(*dom), head); 158 dom = list_entry(dom->head.next, typeof(*dom), head);
154 } while (&dom->head != &ppm->domains); 159 } while (&dom->head != &ppm->domains);
155 160
156 args->iter = 0xffffffff; 161 args->v0.iter = 0xffffffff;
157 return 0; 162 return 0;
158} 163}
159 164
160static int 165static int
161nouveau_perfctr_sample(struct nouveau_object *object, u32 mthd, 166nouveau_perfctr_sample(struct nouveau_object *object, void *data, u32 size)
162 void *data, u32 size)
163{ 167{
168 union {
169 struct nvif_perfctr_sample none;
170 } *args = data;
164 struct nouveau_perfmon *ppm = (void *)object->engine; 171 struct nouveau_perfmon *ppm = (void *)object->engine;
165 struct nouveau_perfctr *ctr, *tmp; 172 struct nouveau_perfctr *ctr, *tmp;
166 struct nouveau_perfdom *dom; 173 struct nouveau_perfdom *dom;
167 struct nv_perfctr_sample *args = data; 174 int ret;
168 175
169 if (size < sizeof(*args)) 176 nv_ioctl(object, "perfctr sample size %d\n", size);
170 return -EINVAL; 177 if (nvif_unvers(args->none)) {
178 nv_ioctl(object, "perfctr sample\n");
179 } else
180 return ret;
171 ppm->sequence++; 181 ppm->sequence++;
172 182
173 list_for_each_entry(dom, &ppm->domains, head) { 183 list_for_each_entry(dom, &ppm->domains, head) {
@@ -206,22 +216,45 @@ nouveau_perfctr_sample(struct nouveau_object *object, u32 mthd,
206} 216}
207 217
208static int 218static int
209nouveau_perfctr_read(struct nouveau_object *object, u32 mthd, 219nouveau_perfctr_read(struct nouveau_object *object, void *data, u32 size)
210 void *data, u32 size)
211{ 220{
221 union {
222 struct nvif_perfctr_read_v0 v0;
223 } *args = data;
212 struct nouveau_perfctr *ctr = (void *)object; 224 struct nouveau_perfctr *ctr = (void *)object;
213 struct nv_perfctr_read *args = data; 225 int ret;
226
227 nv_ioctl(object, "perfctr read size %d\n", size);
228 if (nvif_unpack(args->v0, 0, 0, false)) {
229 nv_ioctl(object, "perfctr read vers %d\n", args->v0.version);
230 } else
231 return ret;
214 232
215 if (size < sizeof(*args))
216 return -EINVAL;
217 if (!ctr->clk) 233 if (!ctr->clk)
218 return -EAGAIN; 234 return -EAGAIN;
219 235
220 args->clk = ctr->clk; 236 args->v0.clk = ctr->clk;
221 args->ctr = ctr->ctr; 237 args->v0.ctr = ctr->ctr;
222 return 0; 238 return 0;
223} 239}
224 240
241static int
242nouveau_perfctr_mthd(struct nouveau_object *object, u32 mthd,
243 void *data, u32 size)
244{
245 switch (mthd) {
246 case NVIF_PERFCTR_V0_QUERY:
247 return nouveau_perfctr_query(object, data, size);
248 case NVIF_PERFCTR_V0_SAMPLE:
249 return nouveau_perfctr_sample(object, data, size);
250 case NVIF_PERFCTR_V0_READ:
251 return nouveau_perfctr_read(object, data, size);
252 default:
253 break;
254 }
255 return -EINVAL;
256}
257
225static void 258static void
226nouveau_perfctr_dtor(struct nouveau_object *object) 259nouveau_perfctr_dtor(struct nouveau_object *object)
227{ 260{
@@ -237,19 +270,27 @@ nouveau_perfctr_ctor(struct nouveau_object *parent,
237 struct nouveau_oclass *oclass, void *data, u32 size, 270 struct nouveau_oclass *oclass, void *data, u32 size,
238 struct nouveau_object **pobject) 271 struct nouveau_object **pobject)
239{ 272{
273 union {
274 struct nvif_perfctr_v0 v0;
275 } *args = data;
240 struct nouveau_perfmon *ppm = (void *)engine; 276 struct nouveau_perfmon *ppm = (void *)engine;
241 struct nouveau_perfdom *dom = NULL; 277 struct nouveau_perfdom *dom = NULL;
242 struct nouveau_perfsig *sig[4] = {}; 278 struct nouveau_perfsig *sig[4] = {};
243 struct nouveau_perfctr *ctr; 279 struct nouveau_perfctr *ctr;
244 struct nv_perfctr_class *args = data;
245 int ret, i; 280 int ret, i;
246 281
247 if (size < sizeof(*args)) 282 nv_ioctl(parent, "create perfctr size %d\n", size);
248 return -EINVAL; 283 if (nvif_unpack(args->v0, 0, 0, false)) {
284 nv_ioctl(parent, "create perfctr vers %d logic_op %04x\n",
285 args->v0.version, args->v0.logic_op);
286 } else
287 return ret;
249 288
250 for (i = 0; i < ARRAY_SIZE(args->signal) && args->signal[i].name; i++) { 289 for (i = 0; i < ARRAY_SIZE(args->v0.name) && args->v0.name[i][0]; i++) {
251 sig[i] = nouveau_perfsig_find(ppm, args->signal[i].name, 290 sig[i] = nouveau_perfsig_find(ppm, args->v0.name[i],
252 args->signal[i].size, &dom); 291 strnlen(args->v0.name[i],
292 sizeof(args->v0.name[i])),
293 &dom);
253 if (!sig[i]) 294 if (!sig[i])
254 return -EINVAL; 295 return -EINVAL;
255 } 296 }
@@ -260,7 +301,7 @@ nouveau_perfctr_ctor(struct nouveau_object *parent,
260 return ret; 301 return ret;
261 302
262 ctr->slot = -1; 303 ctr->slot = -1;
263 ctr->logic_op = args->logic_op; 304 ctr->logic_op = args->v0.logic_op;
264 ctr->signal[0] = sig[0]; 305 ctr->signal[0] = sig[0];
265 ctr->signal[1] = sig[1]; 306 ctr->signal[1] = sig[1];
266 ctr->signal[2] = sig[2]; 307 ctr->signal[2] = sig[2];
@@ -276,21 +317,13 @@ nouveau_perfctr_ofuncs = {
276 .dtor = nouveau_perfctr_dtor, 317 .dtor = nouveau_perfctr_dtor,
277 .init = nouveau_object_init, 318 .init = nouveau_object_init,
278 .fini = nouveau_object_fini, 319 .fini = nouveau_object_fini,
279}; 320 .mthd = nouveau_perfctr_mthd,
280
281static struct nouveau_omthds
282nouveau_perfctr_omthds[] = {
283 { NV_PERFCTR_QUERY, NV_PERFCTR_QUERY, nouveau_perfctr_query },
284 { NV_PERFCTR_SAMPLE, NV_PERFCTR_SAMPLE, nouveau_perfctr_sample },
285 { NV_PERFCTR_READ, NV_PERFCTR_READ, nouveau_perfctr_read },
286 {}
287}; 321};
288 322
289struct nouveau_oclass 323struct nouveau_oclass
290nouveau_perfmon_sclass[] = { 324nouveau_perfmon_sclass[] = {
291 { .handle = NV_PERFCTR_CLASS, 325 { .handle = NVIF_IOCTL_NEW_V0_PERFCTR,
292 .ofuncs = &nouveau_perfctr_ofuncs, 326 .ofuncs = &nouveau_perfctr_ofuncs,
293 .omthds = nouveau_perfctr_omthds,
294 }, 327 },
295 {}, 328 {},
296}; 329};
diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h
index 53004b7a3f46..3df23606eb02 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/class.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/class.h
@@ -3,37 +3,6 @@
3 3
4#include <nvif/class.h> 4#include <nvif/class.h>
5 5
6/* Perfmon counter class
7 *
8 * XXXX: NV_PERFCTR
9 */
10#define NV_PERFCTR_CLASS 0x0000ffff
11#define NV_PERFCTR_QUERY 0x00000000
12#define NV_PERFCTR_SAMPLE 0x00000001
13#define NV_PERFCTR_READ 0x00000002
14
15struct nv_perfctr_class {
16 u16 logic_op;
17 struct {
18 char __user *name; /*XXX: use cfu when exposed to userspace */
19 u32 size;
20 } signal[4];
21};
22
23struct nv_perfctr_query {
24 u32 iter;
25 u32 size;
26 char __user *name; /*XXX: use ctu when exposed to userspace */
27};
28
29struct nv_perfctr_sample {
30};
31
32struct nv_perfctr_read {
33 u32 ctr;
34 u32 clk;
35};
36
37/* Device control class 6/* Device control class
38 * 7 *
39 * XXXX: NV_CONTROL 8 * XXXX: NV_CONTROL
diff --git a/drivers/gpu/drm/nouveau/nvif/class.h b/drivers/gpu/drm/nouveau/nvif/class.h
index 5279d0dd4d6f..decca22ea528 100644
--- a/drivers/gpu/drm/nouveau/nvif/class.h
+++ b/drivers/gpu/drm/nouveau/nvif/class.h
@@ -151,4 +151,38 @@ struct gf110_dma_v0 {
151 __u8 pad03[5]; 151 __u8 pad03[5];
152}; 152};
153 153
154
155/*******************************************************************************
156 * perfmon
157 ******************************************************************************/
158
159struct nvif_perfctr_v0 {
160 __u8 version;
161 __u8 pad01[1];
162 __u16 logic_op;
163 __u8 pad04[4];
164 char name[4][64];
165};
166
167#define NVIF_PERFCTR_V0_QUERY 0x00
168#define NVIF_PERFCTR_V0_SAMPLE 0x01
169#define NVIF_PERFCTR_V0_READ 0x02
170
171struct nvif_perfctr_query_v0 {
172 __u8 version;
173 __u8 pad01[3];
174 __u32 iter;
175 char name[64];
176};
177
178struct nvif_perfctr_sample {
179};
180
181struct nvif_perfctr_read_v0 {
182 __u8 version;
183 __u8 pad01[7];
184 __u32 ctr;
185 __u32 clk;
186};
187
154#endif 188#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/ioctl.h b/drivers/gpu/drm/nouveau/nvif/ioctl.h
index 38f24d1e9f60..67a56711b18c 100644
--- a/drivers/gpu/drm/nouveau/nvif/ioctl.h
+++ b/drivers/gpu/drm/nouveau/nvif/ioctl.h
@@ -48,6 +48,8 @@ struct nvif_ioctl_new_v0 {
48 __u8 route; 48 __u8 route;
49 __u64 token; 49 __u64 token;
50 __u32 handle; 50 __u32 handle;
51/* these class numbers are made up by us, and not nvidia-assigned */
52#define NVIF_IOCTL_NEW_V0_PERFCTR 0x0000ffff
51 __u32 oclass; 53 __u32 oclass;
52 __u8 data[]; /* class data (class.h) */ 54 __u8 data[]; /* class data (class.h) */
53}; 55};