diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2014-08-09 14:10:24 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-08-09 15:13:25 -0400 |
commit | 96af8222cef78ab4d92186d5e10880dc78395415 (patch) | |
tree | b90b8fe780d6e0530dfd98a798a08133ced8823c | |
parent | 4acfd707e28c820ba8ed8c12b497413a133d8c8f (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.c | 127 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/include/core/class.h | 31 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/class.h | 34 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvif/ioctl.h | 2 |
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 | ******************************************************************************/ |
103 | static int | 106 | static int |
104 | nouveau_perfctr_query(struct nouveau_object *object, u32 mthd, | 107 | nouveau_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 | ||
160 | static int | 165 | static int |
161 | nouveau_perfctr_sample(struct nouveau_object *object, u32 mthd, | 166 | nouveau_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 | ||
208 | static int | 218 | static int |
209 | nouveau_perfctr_read(struct nouveau_object *object, u32 mthd, | 219 | nouveau_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 | ||
241 | static int | ||
242 | nouveau_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 | |||
225 | static void | 258 | static void |
226 | nouveau_perfctr_dtor(struct nouveau_object *object) | 259 | nouveau_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 | |||
281 | static struct nouveau_omthds | ||
282 | nouveau_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 | ||
289 | struct nouveau_oclass | 323 | struct nouveau_oclass |
290 | nouveau_perfmon_sclass[] = { | 324 | nouveau_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 | |||
15 | struct 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 | |||
23 | struct nv_perfctr_query { | ||
24 | u32 iter; | ||
25 | u32 size; | ||
26 | char __user *name; /*XXX: use ctu when exposed to userspace */ | ||
27 | }; | ||
28 | |||
29 | struct nv_perfctr_sample { | ||
30 | }; | ||
31 | |||
32 | struct 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 | |||
159 | struct 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 | |||
171 | struct nvif_perfctr_query_v0 { | ||
172 | __u8 version; | ||
173 | __u8 pad01[3]; | ||
174 | __u32 iter; | ||
175 | char name[64]; | ||
176 | }; | ||
177 | |||
178 | struct nvif_perfctr_sample { | ||
179 | }; | ||
180 | |||
181 | struct 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 | }; |