hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/gpu/drm/drm_framebuffer.c
....@@ -21,14 +21,22 @@
2121 */
2222
2323 #include <linux/export.h>
24
-#include <drm/drmP.h>
25
-#include <drm/drm_auth.h>
26
-#include <drm/drm_framebuffer.h>
27
-#include <drm/drm_atomic.h>
28
-#include <drm/drm_print.h>
24
+#include <linux/uaccess.h>
2925
30
-#include "drm_internal.h"
26
+#include <drm/drm_atomic.h>
27
+#include <drm/drm_atomic_uapi.h>
28
+#include <drm/drm_auth.h>
29
+#include <drm/drm_debugfs.h>
30
+#include <drm/drm_drv.h>
31
+#include <drm/drm_file.h>
32
+#include <drm/drm_fourcc.h>
33
+#include <drm/drm_framebuffer.h>
34
+#include <drm/drm_gem.h>
35
+#include <drm/drm_print.h>
36
+#include <drm/drm_util.h>
37
+
3138 #include "drm_crtc_internal.h"
39
+#include "drm_internal.h"
3240
3341 /**
3442 * DOC: overview
....@@ -112,17 +120,21 @@
112120 struct drm_mode_fb_cmd2 r = {};
113121 int ret;
114122
123
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
124
+ return -EOPNOTSUPP;
125
+
126
+ r.pixel_format = drm_driver_legacy_fb_format(dev, or->bpp, or->depth);
127
+ if (r.pixel_format == DRM_FORMAT_INVALID) {
128
+ DRM_DEBUG("bad {bpp:%d, depth:%d}\n", or->bpp, or->depth);
129
+ return -EINVAL;
130
+ }
131
+
115132 /* convert to new format and call new ioctl */
116133 r.fb_id = or->fb_id;
117134 r.width = or->width;
118135 r.height = or->height;
119136 r.pitches[0] = or->pitch;
120
- r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
121137 r.handles[0] = or->handle;
122
-
123
- if (r.pixel_format == DRM_FORMAT_XRGB2101010 &&
124
- dev->driver->driver_features & DRIVER_PREFER_XBGR_30BPP)
125
- r.pixel_format = DRM_FORMAT_XBGR2101010;
126138
127139 ret = drm_mode_addfb2(dev, &r, file_priv);
128140 if (ret)
....@@ -164,8 +176,7 @@
164176 int i;
165177
166178 /* check if the format is supported at all */
167
- info = __drm_format_info(r->pixel_format & ~DRM_FORMAT_BIG_ENDIAN);
168
- if (!info) {
179
+ if (!__drm_format_info(r->pixel_format)) {
169180 struct drm_format_name_buf format_name;
170181
171182 DRM_DEBUG_KMS("bad framebuffer format %s\n",
....@@ -173,9 +184,6 @@
173184 &format_name));
174185 return -EINVAL;
175186 }
176
-
177
- /* now let the driver pick its own format info */
178
- info = drm_get_format_info(dev, r);
179187
180188 if (r->width == 0) {
181189 DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width);
....@@ -187,23 +195,32 @@
187195 return -EINVAL;
188196 }
189197
198
+ /* now let the driver pick its own format info */
199
+ info = drm_get_format_info(dev, r);
200
+
190201 for (i = 0; i < info->num_planes; i++) {
191202 unsigned int width = fb_plane_width(r->width, info, i);
192203 unsigned int height = fb_plane_height(r->height, info, i);
193
- unsigned int bpp = info->bpp[i];
204
+ unsigned int block_size = info->char_per_block[i];
205
+ u64 min_pitch = drm_format_info_min_pitch(info, i, width);
206
+
207
+ if (!block_size && (r->modifier[i] == DRM_FORMAT_MOD_LINEAR)) {
208
+ DRM_DEBUG_KMS("Format requires non-linear modifier for plane %d\n", i);
209
+ return -EINVAL;
210
+ }
194211
195212 if (!r->handles[i]) {
196213 DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
197214 return -EINVAL;
198215 }
199216
200
- if ((uint64_t) width * bpp / 8 > UINT_MAX)
217
+ if (min_pitch > UINT_MAX)
201218 return -ERANGE;
202219
203220 if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX)
204221 return -ERANGE;
205222
206
- if (r->pitches[i] < roundup(width * bpp, 8) / 8) {
223
+ if (block_size && r->pitches[i] < min_pitch) {
207224 DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
208225 return -EINVAL;
209226 }
....@@ -278,8 +295,7 @@
278295 struct drm_framebuffer *fb;
279296 int ret;
280297
281
- if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS |
282
- DRM_MODE_FB_SECURE)) {
298
+ if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) {
283299 DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
284300 return ERR_PTR(-EINVAL);
285301 }
....@@ -313,6 +329,7 @@
313329
314330 return fb;
315331 }
332
+EXPORT_SYMBOL_FOR_TESTS_ONLY(drm_internal_framebuffer_create);
316333
317334 /**
318335 * drm_mode_addfb2 - add an FB to the graphics configuration
....@@ -336,7 +353,7 @@
336353 struct drm_framebuffer *fb;
337354
338355 if (!drm_core_check_feature(dev, DRIVER_MODESET))
339
- return -EINVAL;
356
+ return -EOPNOTSUPP;
340357
341358 fb = drm_internal_framebuffer_create(dev, r, file_priv);
342359 if (IS_ERR(fb))
....@@ -351,6 +368,30 @@
351368 mutex_unlock(&file_priv->fbs_lock);
352369
353370 return 0;
371
+}
372
+
373
+int drm_mode_addfb2_ioctl(struct drm_device *dev,
374
+ void *data, struct drm_file *file_priv)
375
+{
376
+#ifdef __BIG_ENDIAN
377
+ if (!dev->mode_config.quirk_addfb_prefer_host_byte_order) {
378
+ /*
379
+ * Drivers must set the
380
+ * quirk_addfb_prefer_host_byte_order quirk to make
381
+ * the drm_mode_addfb() compat code work correctly on
382
+ * bigendian machines.
383
+ *
384
+ * If they don't they interpret pixel_format values
385
+ * incorrectly for bug compatibility, which in turn
386
+ * implies the ADDFB2 ioctl does not work correctly
387
+ * then. So block it to make userspace fallback to
388
+ * ADDFB.
389
+ */
390
+ DRM_DEBUG_KMS("addfb2 broken on bigendian");
391
+ return -EOPNOTSUPP;
392
+ }
393
+#endif
394
+ return drm_mode_addfb2(dev, data, file_priv);
354395 }
355396
356397 struct drm_mode_rmfb_work {
....@@ -392,7 +433,7 @@
392433 int found = 0;
393434
394435 if (!drm_core_check_feature(dev, DRIVER_MODESET))
395
- return -EINVAL;
436
+ return -EOPNOTSUPP;
396437
397438 fb = drm_framebuffer_lookup(dev, file_priv, fb_id);
398439 if (!fb)
....@@ -469,7 +510,7 @@
469510 int ret;
470511
471512 if (!drm_core_check_feature(dev, DRIVER_MODESET))
472
- return -EINVAL;
513
+ return -EOPNOTSUPP;
473514
474515 fb = drm_framebuffer_lookup(dev, file_priv, r->fb_id);
475516 if (!fb)
....@@ -489,7 +530,7 @@
489530 r->height = fb->height;
490531 r->width = fb->width;
491532 r->depth = fb->format->depth;
492
- r->bpp = fb->format->bpp[0];
533
+ r->bpp = fb->format->cpp[0] * 8;
493534 r->pitch = fb->pitches[0];
494535
495536 /* GET_FB() is an unprivileged ioctl so we must not return a
....@@ -507,7 +548,128 @@
507548
508549 out:
509550 drm_framebuffer_put(fb);
551
+ return ret;
552
+}
510553
554
+/**
555
+ * drm_mode_getfb2 - get extended FB info
556
+ * @dev: drm device for the ioctl
557
+ * @data: data pointer for the ioctl
558
+ * @file_priv: drm file for the ioctl call
559
+ *
560
+ * Lookup the FB given its ID and return info about it.
561
+ *
562
+ * Called by the user via ioctl.
563
+ *
564
+ * Returns:
565
+ * Zero on success, negative errno on failure.
566
+ */
567
+int drm_mode_getfb2_ioctl(struct drm_device *dev,
568
+ void *data, struct drm_file *file_priv)
569
+{
570
+ struct drm_mode_fb_cmd2 *r = data;
571
+ struct drm_framebuffer *fb;
572
+ unsigned int i;
573
+ int ret;
574
+
575
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
576
+ return -EINVAL;
577
+
578
+ fb = drm_framebuffer_lookup(dev, file_priv, r->fb_id);
579
+ if (!fb)
580
+ return -ENOENT;
581
+
582
+ /* For multi-plane framebuffers, we require the driver to place the
583
+ * GEM objects directly in the drm_framebuffer. For single-plane
584
+ * framebuffers, we can fall back to create_handle.
585
+ */
586
+ if (!fb->obj[0] &&
587
+ (fb->format->num_planes > 1 || !fb->funcs->create_handle)) {
588
+ ret = -ENODEV;
589
+ goto out;
590
+ }
591
+
592
+ r->height = fb->height;
593
+ r->width = fb->width;
594
+ r->pixel_format = fb->format->format;
595
+
596
+ r->flags = 0;
597
+ if (dev->mode_config.allow_fb_modifiers)
598
+ r->flags |= DRM_MODE_FB_MODIFIERS;
599
+
600
+ for (i = 0; i < ARRAY_SIZE(r->handles); i++) {
601
+ r->handles[i] = 0;
602
+ r->pitches[i] = 0;
603
+ r->offsets[i] = 0;
604
+ r->modifier[i] = 0;
605
+ }
606
+
607
+ for (i = 0; i < fb->format->num_planes; i++) {
608
+ r->pitches[i] = fb->pitches[i];
609
+ r->offsets[i] = fb->offsets[i];
610
+ if (dev->mode_config.allow_fb_modifiers)
611
+ r->modifier[i] = fb->modifier;
612
+ }
613
+
614
+ /* GET_FB2() is an unprivileged ioctl so we must not return a
615
+ * buffer-handle to non master/root processes! To match GET_FB()
616
+ * just return invalid handles (0) for non masters/root
617
+ * rather than making GET_FB2() privileged.
618
+ */
619
+ if (!drm_is_current_master(file_priv) && !capable(CAP_SYS_ADMIN)) {
620
+ ret = 0;
621
+ goto out;
622
+ }
623
+
624
+ for (i = 0; i < fb->format->num_planes; i++) {
625
+ int j;
626
+
627
+ /* If we reuse the same object for multiple planes, also
628
+ * return the same handle.
629
+ */
630
+ for (j = 0; j < i; j++) {
631
+ if (fb->obj[i] == fb->obj[j]) {
632
+ r->handles[i] = r->handles[j];
633
+ break;
634
+ }
635
+ }
636
+
637
+ if (r->handles[i])
638
+ continue;
639
+
640
+ if (fb->obj[i]) {
641
+ ret = drm_gem_handle_create(file_priv, fb->obj[i],
642
+ &r->handles[i]);
643
+ } else {
644
+ WARN_ON(i > 0);
645
+ ret = fb->funcs->create_handle(fb, file_priv,
646
+ &r->handles[i]);
647
+ }
648
+
649
+ if (ret != 0)
650
+ goto out;
651
+ }
652
+
653
+out:
654
+ if (ret != 0) {
655
+ /* Delete any previously-created handles on failure. */
656
+ for (i = 0; i < ARRAY_SIZE(r->handles); i++) {
657
+ int j;
658
+
659
+ if (r->handles[i])
660
+ drm_gem_handle_delete(file_priv, r->handles[i]);
661
+
662
+ /* Zero out any handles identical to the one we just
663
+ * deleted.
664
+ */
665
+ for (j = i + 1; j < ARRAY_SIZE(r->handles); j++) {
666
+ if (r->handles[j] == r->handles[i])
667
+ r->handles[j] = 0;
668
+ }
669
+ }
670
+ }
671
+
672
+ drm_framebuffer_put(fb);
511673 return ret;
512674 }
513675
....@@ -542,7 +704,7 @@
542704 int ret;
543705
544706 if (!drm_core_check_feature(dev, DRIVER_MODESET))
545
- return -EINVAL;
707
+ return -EOPNOTSUPP;
546708
547709 fb = drm_framebuffer_lookup(dev, file_priv, r->fb_id);
548710 if (!fb)
....@@ -737,7 +899,7 @@
737899 * @fb: fb to unregister
738900 *
739901 * Drivers need to call this when cleaning up driver-private framebuffers, e.g.
740
- * those used for fbdev. Note that the caller must hold a reference of it's own,
902
+ * those used for fbdev. Note that the caller must hold a reference of its own,
741903 * i.e. the object may not be destroyed through this call (since it'll lead to a
742904 * locking inversion).
743905 *
....@@ -947,6 +1109,7 @@
9471109 if (drm_framebuffer_read_refcount(fb) > 1) {
9481110 if (drm_drv_uses_atomic_modeset(dev)) {
9491111 int ret = atomic_remove_fb(fb);
1112
+
9501113 WARN(ret, "atomic remove_fb failed with %i\n", ret);
9511114 } else
9521115 legacy_remove_fb(fb);
....@@ -1044,10 +1207,10 @@
10441207 { "framebuffer", drm_framebuffer_info, 0 },
10451208 };
10461209
1047
-int drm_framebuffer_debugfs_init(struct drm_minor *minor)
1210
+void drm_framebuffer_debugfs_init(struct drm_minor *minor)
10481211 {
1049
- return drm_debugfs_create_files(drm_framebuffer_debugfs_list,
1050
- ARRAY_SIZE(drm_framebuffer_debugfs_list),
1051
- minor->debugfs_root, minor);
1212
+ drm_debugfs_create_files(drm_framebuffer_debugfs_list,
1213
+ ARRAY_SIZE(drm_framebuffer_debugfs_list),
1214
+ minor->debugfs_root, minor);
10521215 }
10531216 #endif