Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/etnaviv: copy pmrs from userspace

Changes from v1 -> v2:
- renamed submit_perfmon_request() to submit_perfmon_validate()
- extended flags validation
- added comment about offset 0
- moved assigment of cmdbuf->nr_pmrs below the copy_from_user of the pmrs.

Changes from v2 -> v3:
- fixed flags validation

Changes v4 -> v5
- pass cmdbuf->exec_state to etnaviv_pm_req_validate(..)

Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>

authored by

Christian Gmeiner and committed by
Lucas Stach
c8e4a7fd 46df52cd

+67 -2
+67 -2
drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
··· 21 21 #include "etnaviv_drv.h" 22 22 #include "etnaviv_gpu.h" 23 23 #include "etnaviv_gem.h" 24 + #include "etnaviv_perfmon.h" 24 25 25 26 /* 26 27 * Cmdstream submission: ··· 284 283 return 0; 285 284 } 286 285 286 + static int submit_perfmon_validate(struct etnaviv_gem_submit *submit, 287 + struct etnaviv_cmdbuf *cmdbuf, 288 + const struct drm_etnaviv_gem_submit_pmr *pmrs, 289 + u32 nr_pms) 290 + { 291 + u32 i; 292 + 293 + for (i = 0; i < nr_pms; i++) { 294 + const struct drm_etnaviv_gem_submit_pmr *r = pmrs + i; 295 + struct etnaviv_gem_submit_bo *bo; 296 + int ret; 297 + 298 + ret = submit_bo(submit, r->read_idx, &bo); 299 + if (ret) 300 + return ret; 301 + 302 + /* at offset 0 a sequence number gets stored used for userspace sync */ 303 + if (r->read_offset == 0) { 304 + DRM_ERROR("perfmon request: offset is 0"); 305 + return -EINVAL; 306 + } 307 + 308 + if (r->read_offset >= bo->obj->base.size - sizeof(u32)) { 309 + DRM_ERROR("perfmon request: offset %u outside object", i); 310 + return -EINVAL; 311 + } 312 + 313 + if (r->flags & ~(ETNA_PM_PROCESS_PRE | ETNA_PM_PROCESS_POST)) { 314 + DRM_ERROR("perfmon request: flags are not valid"); 315 + return -EINVAL; 316 + } 317 + 318 + if (etnaviv_pm_req_validate(r, cmdbuf->exec_state)) { 319 + DRM_ERROR("perfmon request: domain or signal not valid"); 320 + return -EINVAL; 321 + } 322 + 323 + cmdbuf->pmrs[i].flags = r->flags; 324 + cmdbuf->pmrs[i].domain = r->domain; 325 + cmdbuf->pmrs[i].signal = r->signal; 326 + cmdbuf->pmrs[i].sequence = r->sequence; 327 + cmdbuf->pmrs[i].offset = r->read_offset; 328 + cmdbuf->pmrs[i].bo_vma = etnaviv_gem_vmap(&bo->obj->base); 329 + } 330 + 331 + return 0; 332 + } 333 + 287 334 static void submit_cleanup(struct etnaviv_gem_submit *submit) 288 335 { 289 336 unsigned i; ··· 355 306 struct etnaviv_drm_private *priv = dev->dev_private; 356 307 struct drm_etnaviv_gem_submit *args = data; 357 308 struct drm_etnaviv_gem_submit_reloc *relocs; 309 + struct drm_etnaviv_gem_submit_pmr *pmrs; 358 310 struct drm_etnaviv_gem_submit_bo *bos; 359 311 struct etnaviv_gem_submit *submit; 360 312 struct etnaviv_cmdbuf *cmdbuf; ··· 397 347 */ 398 348 bos = kvmalloc_array(args->nr_bos, sizeof(*bos), GFP_KERNEL); 399 349 relocs = kvmalloc_array(args->nr_relocs, sizeof(*relocs), GFP_KERNEL); 350 + pmrs = kvmalloc_array(args->nr_pmrs, sizeof(*pmrs), GFP_KERNEL); 400 351 stream = kvmalloc_array(1, args->stream_size, GFP_KERNEL); 401 352 cmdbuf = etnaviv_cmdbuf_new(gpu->cmdbuf_suballoc, 402 353 ALIGN(args->stream_size, 8) + 8, 403 - args->nr_bos, 0); 404 - if (!bos || !relocs || !stream || !cmdbuf) { 354 + args->nr_bos, args->nr_pmrs); 355 + if (!bos || !relocs || !pmrs || !stream || !cmdbuf) { 405 356 ret = -ENOMEM; 406 357 goto err_submit_cmds; 407 358 } ··· 423 372 ret = -EFAULT; 424 373 goto err_submit_cmds; 425 374 } 375 + 376 + ret = copy_from_user(pmrs, u64_to_user_ptr(args->pmrs), 377 + args->nr_pmrs * sizeof(*pmrs)); 378 + if (ret) { 379 + ret = -EFAULT; 380 + goto err_submit_cmds; 381 + } 382 + cmdbuf->nr_pmrs = args->nr_pmrs; 426 383 427 384 ret = copy_from_user(stream, u64_to_user_ptr(args->stream), 428 385 args->stream_size); ··· 500 441 if (ret) 501 442 goto out; 502 443 444 + ret = submit_perfmon_validate(submit, cmdbuf, pmrs, args->nr_pmrs); 445 + if (ret) 446 + goto out; 447 + 503 448 memcpy(cmdbuf->vaddr, stream, args->stream_size); 504 449 cmdbuf->user_size = ALIGN(args->stream_size, 8); 505 450 ··· 557 494 kvfree(bos); 558 495 if (relocs) 559 496 kvfree(relocs); 497 + if (pmrs) 498 + kvfree(pmrs); 560 499 561 500 return ret; 562 501 }