+static bool
+check_fbo_size(struct exec_info *exec, struct drm_gem_cma_object *fbo,
+ uint32_t offset, uint8_t tiling_format, uint8_t cpp)
+{
+ uint32_t width_align, height_align;
+ uint32_t aligned_row_len, aligned_h, size;
+
+ switch (tiling_format) {
+ case VC4_TILING_FORMAT_LINEAR:
+ width_align = 16;
+ height_align = 1;
+ break;
+ case VC4_TILING_FORMAT_T:
+ width_align = 128;
+ height_align = 32;
+ break;
+ case VC4_TILING_FORMAT_LT:
+ width_align = 16;
+ height_align = 4;
+ break;
+ default:
+ DRM_ERROR("buffer tiling %d unsupported\n", tiling_format);
+ return false;
+ }
+
+ /* The values are limited by the packet bitfields, so we don't need to
+ * worry as much about integer overflow.
+ */
+ BUG_ON(exec->fb_width > 65535);
+ BUG_ON(exec->fb_height > 65535);
+
+ aligned_row_len = roundup(exec->fb_width * cpp, width_align);
+ aligned_h = roundup(exec->fb_height, height_align);
+
+ if (INT_MAX / aligned_row_len < aligned_h) {
+ DRM_ERROR("Overflow in fbo size (%d * %d)\n",
+ aligned_row_len, aligned_h);
+ return false;
+ }
+ size = aligned_row_len * aligned_h;
+
+ if (size + offset < size ||
+ size + offset > fbo->base.size) {
+ DRM_ERROR("Overflow in %dx%d fbo size (%d + %d > %d)\n",
+ exec->fb_width, exec->fb_height, size, offset,
+ fbo->base.size);
+ return false;
+ }
+
+ return true;
+}
+