diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 1c564edd497e..9163efd676dd 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -60,11 +60,14 @@ static const struct drm_fb_helper_funcs exynos_drm_fbdev_helper_funcs = { int exynos_drm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { - struct exynos_drm_gem *exynos_gem; struct drm_device *dev = helper->dev; struct fb_info *info = helper->info; + u32 fourcc, pitch; + u64 size; + const struct drm_format_info *format; + struct exynos_drm_gem *exynos_gem; + struct drm_gem_object *obj; struct drm_mode_fb_cmd2 mode_cmd = { 0 }; - unsigned long size; int ret; DRM_DEV_DEBUG_KMS(dev->dev, @@ -72,23 +75,33 @@ int exynos_drm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, sizes->surface_width, sizes->surface_height, sizes->surface_bpp); - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - mode_cmd.pitches[0] = sizes->surface_width * (sizes->surface_bpp >> 3); - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - size = mode_cmd.pitches[0] * mode_cmd.height; + fourcc = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); + if (fourcc == DRM_FORMAT_INVALID) + return -EINVAL; + format = drm_get_format_info(dev, fourcc, DRM_FORMAT_MOD_LINEAR); + if (!format) + return -EINVAL; + pitch = drm_format_info_min_pitch(format, 0, sizes->surface_width); + if (!pitch) + return -EINVAL; + if (check_mul_overflow(pitch, sizes->surface_height, &size)) + return -EINVAL; + size = ALIGN(size, PAGE_SIZE); + if (size < PAGE_SIZE) + return -EINVAL; exynos_gem = exynos_drm_gem_create(dev, EXYNOS_BO_WC, size, true); if (IS_ERR(exynos_gem)) return PTR_ERR(exynos_gem); + obj = &exynos_gem->base; - helper->fb = - exynos_drm_framebuffer_init(dev, - drm_get_format_info(dev, mode_cmd.pixel_format, - mode_cmd.modifier[0]), - &mode_cmd, &exynos_gem, 1); + mode_cmd.width = sizes->surface_width; + mode_cmd.height = sizes->surface_height; + mode_cmd.pixel_format = fourcc; + mode_cmd.pitches[0] = pitch; + mode_cmd.modifier[0] = DRM_FORMAT_MOD_LINEAR; + + helper->fb = exynos_drm_framebuffer_init(dev, format, &mode_cmd, &exynos_gem, 1); if (IS_ERR(helper->fb)) { DRM_DEV_ERROR(dev->dev, "failed to create drm framebuffer.\n"); ret = PTR_ERR(helper->fb); @@ -102,8 +115,8 @@ int exynos_drm_fbdev_driver_fbdev_probe(struct drm_fb_helper *helper, info->flags |= FBINFO_VIRTFB; info->screen_buffer = exynos_gem->kvaddr; - info->screen_size = size; - info->fix.smem_len = size; + info->screen_size = obj->size; + info->fix.smem_len = obj->size; return 0;