[RFT,v2,1/5] drm: Split framebuffer pixel offset calculation from drm_fb_dma_get_gem_addr()
| Message ID | 20260916033327.3054126-2-wenst@chromium.org (mailing list archive) |
|---|---|
| State | New |
| Headers |
Return-Path: <linux-sunxi+bounces-25965-sunxi=pue.re@lists.linux.dev>
X-Original-To: noreply@patchwork.local
Delivered-To: noreply@patchwork.local
Received: from tor.lore.kernel.org (tor.lore.kernel.org [172.105.105.114])
by mxe881.netcup.net (Postfix) with ESMTPS id A06D81C31AB
for <noreply@patchwork.local>; Wed, 16 Sep 2026 05:36:03 +0200 (CEST)
Authentication-Results: mxe881;
dkim=pass header.d=chromium.org;
spf=pass (sender IP is 172.105.105.114)
smtp.mailfrom=linux-sunxi+bounces-25965-noreply=patchwork.local@lists.linux.dev
smtp.helo=tor.lore.kernel.org
Received-SPF: pass (mxe881: domain of lists.linux.dev designates
172.105.105.114 as permitted sender) client-ip=172.105.105.114;
envelope-from=linux-sunxi+bounces-25965-noreply=patchwork.local@lists.linux.dev;
helo=tor.lore.kernel.org;
Received: from smtp.subspace.kernel.org (conduit.subspace.kernel.org
[100.90.174.1])
by tor.lore.kernel.org (Postfix) with ESMTP id 1A9AF347B8
for <noreply@patchwork.local>; Wed, 16 Sep 2026 03:33:46 +0000 (UTC)
Received: from localhost.localdomain (localhost.localdomain [127.0.0.1])
by smtp.subspace.kernel.org (Postfix) with ESMTP id 629352F39C7;
Wed, 16 Sep 2026 03:33:43 +0000 (UTC)
Authentication-Results: smtp.subspace.kernel.org;
dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org
header.b="KgqWrZpw"
X-Original-To: linux-sunxi@lists.linux.dev
Received: from mail-pj2-f43.google.com (mail-pj2-f43.google.com
[74.125.227.171])
(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))
(No client certificate requested)
by smtp.subspace.kernel.org (Postfix) with ESMTPS id AFCA8389E1A
for <linux-sunxi@lists.linux.dev>; Wed, 16 Sep 2026 03:33:41 +0000 (UTC)
Authentication-Results: smtp.subspace.kernel.org;
arc=none smtp.client-ip=74.125.227.171
ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;
t=1789529623; cv=none;
b=QKfWt6eAYX2ro8PuK2w9qugYzh4LGNgKHQkcpp5G6iWn0PQhj7XHzQ3iv6R+fx+MIydfUc2VNPHRpGIvfVJWYzJNf6+/qvqQSQSxExPeby4A5AicdFHA/AjU1MIsSyAwqsLYCwofQ2MM7X0JvF/UIPAB4tD3kdvDQ0epm8DbfIQ=
ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org;
s=arc-20240116; t=1789529623; c=relaxed/simple;
bh=es80KIPm6d34RQhtEPnuboKLoKRoUcyHS9QbOTgsSi8=;
h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:
MIME-Version;
b=biUYWbaCUEikznJWRl4yX2/2c1DIMNgaZ0AQlNSkENjOg+w0fWk5/CGyrAbjkuC36Rik1LShp0Hb5YO8FDIhTJHcU0Idlz3/l+Xn6MZBcavjy/ZrK0AKZN6n6/2KUgVthhuEjiMZMHD7H6TlZU/ivnJG7hhC8+521vG8FSp/P+s=
ARC-Authentication-Results: i=1; smtp.subspace.kernel.org;
dmarc=pass (p=none dis=none) header.from=chromium.org;
spf=pass smtp.mailfrom=chromium.org;
dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org
header.b=KgqWrZpw; arc=none smtp.client-ip=74.125.227.171
Authentication-Results: smtp.subspace.kernel.org;
dmarc=pass (p=none dis=none) header.from=chromium.org
Authentication-Results: smtp.subspace.kernel.org;
spf=pass smtp.mailfrom=chromium.org
Received: by mail-pj2-f43.google.com with SMTP id
98e67ed59e1d1-396ccb1a98dso346935a91.0
for <linux-sunxi@lists.linux.dev>;
Tue, 15 Sep 2026 20:33:41 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=chromium.org; s=google; t=1789529621; x=1790134421;
darn=lists.linux.dev;
h=content-transfer-encoding:mime-version:references:in-reply-to
:message-id:date:subject:cc:to:from:from:to:cc:subject:date
:message-id:reply-to:content-type;
bh=JETOMAWav2dfMHsWYPyuoNMSTDJN0FsRCfFHE94te6U=;
b=KgqWrZpw/MzjdNzJk8uKHXWRzRYVkE8Xjm6mT4e/BZzzJoH97P3F0EA+26vlox7EM9
5v40UUpF2p6Uh1WeSJROb64t71jp9Q8xd/zWuNOpqy8Njf1PLtnmqpGTRRAfviOxYg/2
2ftDT6Dz/iAYOAuY9ylGTfh9ZDm+zkI0q+U60=
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20260707; t=1789529621; x=1790134421;
h=content-transfer-encoding:mime-version:references:in-reply-to
:message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from
:to:cc:subject:date:message-id:reply-to:content-type;
bh=JETOMAWav2dfMHsWYPyuoNMSTDJN0FsRCfFHE94te6U=;
b=T+Uc5bFFm8yj+lWWNuuND879IYCj2iFxb9bA+T6qZT+D9oLoVAL/V9mQ0YWmxa+T+Y
q8y+fLNK+0FGQASoFPp3boi7YaED1qMQXrlLKIwEDG/2cK5KoRzj1+crEbWyGXXNbAde
qRwVIUv/M98W6XPFkamqNuk3V1nr8pY+GNgRV+3fnfpIK+UZQUgLrkcnv/mddxg0IXnJ
aqAGinJDRC0rcj54tVJ/hH3urFl6TmqoJmbFuYghZD3jfY2xn6TMIm/K0KeaAQWsaOfR
RPhzlae1UmapRk4uyGn89BwNTYt9yGWQqM8ZXkVovk282CQYjxf8vIspvjTfc00C9mza
5vyQ==
X-Forwarded-Encrypted: i=1;
AKwUvBy31RK/9O8tNXgQiCqQE4o/O709XYPJI69C6Y5+diLvof9PHUXybdiiNahi8c4oepKH2922oddWyyd7og==@lists.linux.dev
X-Gm-Message-State: AFuF++m3I2OxkJbXKAg07F9S/khaQuuYI878SlsbmlJiKbeya126vaE9
P33+Mfp1P4q8kDWTYGDmHi5QZOL/UbO2Ara8tkcYhhlzMEQG4xjEVVXBTX6ee/YFmw==
X-Gm-Gg: AYBFou2BlVSu4FcXf76bw8/xqWKwXQmE8IPNSd+D1uS5YELxzaH4Qqp9eSxjNu2n1oN
CmvK9BgL9pFYEFMquX1JRyyObMTZVSWf52tJP/NAPiwISKKbYlSv3+6tBAl3srm5WGgiZh9UGFm
GoA+xqoX2Pxsb3zivV+y8fHLkcaSO60IIhtpJQ6v5c5ByXIuW6wp+vpftZ0ARRVg7JG4irs4T56
2uPCa+jdGOvfUyLgp5w64GYe33NhZvkYy9yLwdk1p+g+GcLcemkwRyVRZIiUXtEOOIGexmU64Vz
6J9GWpvsLTmK+pDx/M45WThQkH4nAgGNOn1fiC102qFNYH8I5DScstCPsRilMaieogdofJu1dDq
7cY64s06gQ/LyfUpRwwli3NCr5i+YxII/6sBqjMYuWGU2J6UPIVxBWH6Gt3M/0USIvsmKMGIDOn
rcgw+C9sFdi7dGBl+L0NJZ6XJfr012JPZwU1BuXC2RcN78C+X7KNqm2/qHISFnxctj9kcmhvOLu
zLuJEBmgxLJBmJyzjl0TN5KBCHmXl9X0O839suUeBGVIMxDLY0LdqME1Q==
X-Received: by 2002:a17:90b:2604:b0:38e:659b:f366 with SMTP id
98e67ed59e1d1-39e1df6c05dmr2364892a91.0.1789529621075;
Tue, 15 Sep 2026 20:33:41 -0700 (PDT)
Received: from wenst-7875.tpe.corp.google.com
([2a00:79e0:203d:7:1f62:7622:5d61:2578])
by smtp.gmail.com with ESMTPSA id
98e67ed59e1d1-39e1bbe3e62sm1833477a91.10.2026.09.15.20.33.37
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Tue, 15 Sep 2026 20:33:40 -0700 (PDT)
From: Chen-Yu Tsai <wenst@chromium.org>
To: Liu Ying <victor.liu@nxp.com>,
Laurentiu Palcu <laurentiu.palcu@oss.nxp.com>,
Lucas Stach <l.stach@pengutronix.de>,
Chen-Yu Tsai <wens@kernel.org>,
Jernej Skrabec <jernej@kernel.org>,
Samuel Holland <samuel@sholland.org>,
Maarten Lankhorst <maarten.lankhorst@linux.intel.com>,
Maxime Ripard <mripard@kernel.org>,
Thomas Zimmermann <tzimmermann@suse.de>
Cc: Chen-Yu Tsai <wenst@chromium.org>,
David Airlie <airlied@gmail.com>,
Simona Vetter <simona@ffwll.ch>,
linux-sunxi@lists.linux.dev,
imx@lists.linux.dev,
dri-devel@lists.freedesktop.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org,
stable@vger.kernel.org
Subject: [PATCH RFT v2 1/5] drm: Split framebuffer pixel offset calculation
from drm_fb_dma_get_gem_addr()
Date: Wed, 16 Sep 2026 11:33:22 +0800
Message-ID: <20260916033327.3054126-2-wenst@chromium.org>
X-Mailer: git-send-email 2.55.0.1032.g73a4cd73de-goog
In-Reply-To: <20260916033327.3054126-1-wenst@chromium.org>
References: <20260916033327.3054126-1-wenst@chromium.org>
Precedence: bulk
X-Mailing-List: linux-sunxi@lists.linux.dev
List-Id: <linux-sunxi.lists.linux.dev>
List-Subscribe: <mailto:linux-sunxi+subscribe@lists.linux.dev>
List-Unsubscribe: <mailto:linux-sunxi+unsubscribe@lists.linux.dev>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-Rspamd-Server: rspamd-worker-8404
X-Spamd-Result: default: False [-1.16 / 15.00];
BAYES_HAM(-5.50)[100.00%];
RBL_SENDERSCORE(2.00)[172.105.105.114:from];
DMARC_POLICY_SOFTFAIL(1.00)[chromium.org : SPF not aligned (relaxed),
No valid DKIM,none];
MID_CONTAINS_FROM(1.00)[];
R_MISSING_CHARSET(0.50)[];
MAILLIST(-0.15)[generic];
BAD_REP_POLICIES(0.10)[];
MIME_GOOD(-0.10)[text/plain];
HAS_LIST_UNSUB(-0.01)[];
FROM_HAS_DN(0.00)[];
PRECEDENCE_BULK(0.00)[];
RCPT_COUNT_TWELVE(0.00)[18];
FREEMAIL_CC(0.00)[chromium.org,gmail.com,ffwll.ch,lists.linux.dev,lists.freedesktop.org,lists.infradead.org,vger.kernel.org];
DBL_BLOCKED_OPENRESOLVER(0.00)[suse.de:email,tor.lore.kernel.org:rdns,tor.lore.kernel.org:helo,chromium.org:email];
RCVD_COUNT_FIVE(0.00)[6];
FROM_NEQ_ENVFROM(0.00)[wenst@chromium.org,linux-sunxi@lists.linux.dev];
ARC_ALLOW(0.00)[subspace.kernel.org:s=arc-20240116:i=1];
TO_DN_SOME(0.00)[];
R_SPF_ALLOW(0.00)[+ip4:172.105.105.114];
RECEIVED_SPAMHAUS_BLOCKED_OPENRESOLVER(0.00)[74.125.227.171:received,100.90.174.1:received,2a00:79e0:203d:7:1f62:7622:5d61:2578:received];
RBL_SPAMHAUS_BLOCKED_OPENRESOLVER(0.00)[172.105.105.114:from];
FORGED_SENDER_MAILLIST(0.00)[];
FORGED_RECIPIENTS_MAILLIST(0.00)[];
RCVD_TLS_LAST(0.00)[];
MIME_TRACE(0.00)[0:+];
TAGGED_FROM(0.00)[bounces-25965-noreply=patchwork.local];
ASN(0.00)[asn:63949, ipnet:172.105.96.0/20, country:SG];
RCVD_VIA_SMTP_AUTH(0.00)[]
X-Rspamd-Queue-Id: A06D81C31AB
X-MORS-Enabled: yes
X-MORS-DOMAIN: patchwork.local
X-MORS-HOSTING: hosting172546
X-MORS-USER: hosting172546
X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?=
|
| Series |
drm: Add and use drm_fb_dma_get_gem_clipped_addr() helper
|
|
Commit Message
Chen-Yu Tsai
Sept. 16, 2026, 3:33 a.m. UTC
Currently drm_fb_dma_get_gem_addr() calculates the offset into the
framebuffer memory for the framebuffer's unclipped source coordinates,
adds that to the framebuffer's backing storage, and returns the result.
We are about to add a variant that uses the clipped source coordinates,
so there is already some reuse of code. However, calculating the data
offset for a given pixel is not specific to the DMA FB helpers. The
offset is only related to the framebuffer.
Split out the offset calculation into a new framebuffer helper so that
non-DMA users can also reuse the same code.
Suggested-by: Thomas Zimmermann <tzimmermann@suse.de>
Cc: <stable@vger.kernel.org> # dependency for next patch
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v1:
- New patch
---
drivers/gpu/drm/drm_fb_dma_helper.c | 28 ++----------------
drivers/gpu/drm/drm_framebuffer.c | 45 +++++++++++++++++++++++++++++
include/drm/drm_framebuffer.h | 3 ++
3 files changed, 51 insertions(+), 25 deletions(-)
Comments
Hi Am 16.09.26 um 05:33 schrieb Chen-Yu Tsai: > Currently drm_fb_dma_get_gem_addr() calculates the offset into the > framebuffer memory for the framebuffer's unclipped source coordinates, > adds that to the framebuffer's backing storage, and returns the result. > > We are about to add a variant that uses the clipped source coordinates, > so there is already some reuse of code. However, calculating the data > offset for a given pixel is not specific to the DMA FB helpers. The > offset is only related to the framebuffer. > > Split out the offset calculation into a new framebuffer helper so that > non-DMA users can also reuse the same code. > > Suggested-by: Thomas Zimmermann <tzimmermann@suse.de> > Cc: <stable@vger.kernel.org> # dependency for next patch > Signed-off-by: Chen-Yu Tsai <wenst@chromium.org> > --- > Changes since v1: > - New patch > --- > drivers/gpu/drm/drm_fb_dma_helper.c | 28 ++---------------- > drivers/gpu/drm/drm_framebuffer.c | 45 +++++++++++++++++++++++++++++ > include/drm/drm_framebuffer.h | 3 ++ > 3 files changed, 51 insertions(+), 25 deletions(-) > > diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c > index fd71969d2fb1..ab0f37d8a5ff 100644 > --- a/drivers/gpu/drm/drm_fb_dma_helper.c > +++ b/drivers/gpu/drm/drm_fb_dma_helper.c > @@ -75,36 +75,14 @@ dma_addr_t drm_fb_dma_get_gem_addr(struct drm_framebuffer *fb, > unsigned int plane) > { > struct drm_gem_dma_object *obj; > - dma_addr_t dma_addr; > - u8 h_div = 1, v_div = 1; > - u32 block_w = drm_format_info_block_width(fb->format, plane); > - u32 block_h = drm_format_info_block_height(fb->format, plane); > - u32 block_size = fb->format->char_per_block[plane]; > - u32 sample_x; > - u32 sample_y; > - u32 block_start_y; > - u32 num_hblocks; > > obj = drm_fb_dma_get_gem_obj(fb, plane); > if (!obj) > return 0; > > - dma_addr = obj->dma_addr + fb->offsets[plane]; > - > - if (plane > 0) { > - h_div = fb->format->hsub; > - v_div = fb->format->vsub; > - } > - > - sample_x = (state->src_x >> 16) / h_div; > - sample_y = (state->src_y >> 16) / v_div; > - block_start_y = (sample_y / block_h) * block_h; > - num_hblocks = sample_x / block_w; > - > - dma_addr += fb->pitches[plane] * block_start_y; > - dma_addr += block_size * num_hblocks; > - > - return dma_addr; > + return obj->dma_addr + drm_framebuffer_get_block_offset(fb, plane, > + state->src_x >> 16, > + state->src_y >> 16); > } > EXPORT_SYMBOL_GPL(drm_fb_dma_get_gem_addr); > > diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c > index d32aceb6ca9b..9e1231162047 100644 > --- a/drivers/gpu/drm/drm_framebuffer.c > +++ b/drivers/gpu/drm/drm_framebuffer.c > @@ -1208,6 +1208,51 @@ void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, > } > } > > +/** > + * drm_framebuffer_get_block_offset() - Get offset to start of pixel block for > + * the given framebuffer and coordinates. > + * @fb: The framebuffer > + * @plane: Which plane > + * @x: x coordinate for pixel > + * @y: y coordinate for pixel > + * > + * This function will usually be called from the PLANE callback functions, > + * or from one of the helpers that calculates the framebuffer's DMA address. > + * > + * Return: offset from start of framebuffer to start of pixel block > + */ > +u32 drm_framebuffer_get_block_offset(struct drm_framebuffer *fb, unsigned int plane, > + unsigned int x, unsigned int y) Better use u64 as return type. > +{ > + u8 h_div = 1, v_div = 1; > + u32 block_w = drm_format_info_block_width(fb->format, plane); > + u32 block_h = drm_format_info_block_height(fb->format, plane); > + u32 block_size = fb->format->char_per_block[plane]; > + u32 sample_x; > + u32 sample_y; > + u32 block_start_y; > + u32 num_hblocks; > + u32 offset; > + > + offset = fb->offsets[plane]; > + > + if (plane > 0) { > + h_div = fb->format->hsub; > + v_div = fb->format->vsub; > + } > + > + sample_x = x / h_div; > + sample_y = y / v_div; > + block_start_y = (sample_y / block_h) * block_h; > + num_hblocks = sample_x / block_w; > + > + offset += fb->pitches[plane] * block_start_y; > + offset += block_size * num_hblocks; User space controls the values in fb->offsets and fb->pitches. I'm not sure how well they have been validated already at this point. Did you investigate this? Best regards Thomas > + > + return offset; > +} > +EXPORT_SYMBOL(drm_framebuffer_get_block_offset); > + > #ifdef CONFIG_DEBUG_FS > static int drm_framebuffer_info(struct seq_file *m, void *data) > { > diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h > index 38b24fc8978d..c07aea1cc59f 100644 > --- a/include/drm/drm_framebuffer.h > +++ b/include/drm/drm_framebuffer.h > @@ -220,6 +220,9 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb); > void drm_framebuffer_cleanup(struct drm_framebuffer *fb); > void drm_framebuffer_unregister_private(struct drm_framebuffer *fb); > > +u32 drm_framebuffer_get_block_offset(struct drm_framebuffer *fb, unsigned int plane, > + unsigned int x, unsigned int y); > + > /** > * drm_framebuffer_get - acquire a framebuffer reference > * @fb: DRM framebuffer
On Thu, Sep 17, 2026 at 11:20 PM Thomas Zimmermann <tzimmermann@suse.de> wrote: > > Hi > > Am 16.09.26 um 05:33 schrieb Chen-Yu Tsai: > > Currently drm_fb_dma_get_gem_addr() calculates the offset into the > > framebuffer memory for the framebuffer's unclipped source coordinates, > > adds that to the framebuffer's backing storage, and returns the result. > > > > We are about to add a variant that uses the clipped source coordinates, > > so there is already some reuse of code. However, calculating the data > > offset for a given pixel is not specific to the DMA FB helpers. The > > offset is only related to the framebuffer. > > > > Split out the offset calculation into a new framebuffer helper so that > > non-DMA users can also reuse the same code. > > > > Suggested-by: Thomas Zimmermann <tzimmermann@suse.de> > > Cc: <stable@vger.kernel.org> # dependency for next patch > > Signed-off-by: Chen-Yu Tsai <wenst@chromium.org> > > --- > > Changes since v1: > > - New patch > > --- > > drivers/gpu/drm/drm_fb_dma_helper.c | 28 ++---------------- > > drivers/gpu/drm/drm_framebuffer.c | 45 +++++++++++++++++++++++++++++ > > include/drm/drm_framebuffer.h | 3 ++ > > 3 files changed, 51 insertions(+), 25 deletions(-) > > > > diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c > > index fd71969d2fb1..ab0f37d8a5ff 100644 > > --- a/drivers/gpu/drm/drm_fb_dma_helper.c > > +++ b/drivers/gpu/drm/drm_fb_dma_helper.c > > @@ -75,36 +75,14 @@ dma_addr_t drm_fb_dma_get_gem_addr(struct drm_framebuffer *fb, > > unsigned int plane) > > { > > struct drm_gem_dma_object *obj; > > - dma_addr_t dma_addr; > > - u8 h_div = 1, v_div = 1; > > - u32 block_w = drm_format_info_block_width(fb->format, plane); > > - u32 block_h = drm_format_info_block_height(fb->format, plane); > > - u32 block_size = fb->format->char_per_block[plane]; > > - u32 sample_x; > > - u32 sample_y; > > - u32 block_start_y; > > - u32 num_hblocks; > > > > obj = drm_fb_dma_get_gem_obj(fb, plane); > > if (!obj) > > return 0; > > > > - dma_addr = obj->dma_addr + fb->offsets[plane]; > > - > > - if (plane > 0) { > > - h_div = fb->format->hsub; > > - v_div = fb->format->vsub; > > - } > > - > > - sample_x = (state->src_x >> 16) / h_div; > > - sample_y = (state->src_y >> 16) / v_div; > > - block_start_y = (sample_y / block_h) * block_h; > > - num_hblocks = sample_x / block_w; > > - > > - dma_addr += fb->pitches[plane] * block_start_y; > > - dma_addr += block_size * num_hblocks; > > - > > - return dma_addr; > > + return obj->dma_addr + drm_framebuffer_get_block_offset(fb, plane, > > + state->src_x >> 16, > > + state->src_y >> 16); > > } > > EXPORT_SYMBOL_GPL(drm_fb_dma_get_gem_addr); > > > > diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c > > index d32aceb6ca9b..9e1231162047 100644 > > --- a/drivers/gpu/drm/drm_framebuffer.c > > +++ b/drivers/gpu/drm/drm_framebuffer.c > > @@ -1208,6 +1208,51 @@ void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, > > } > > } > > > > +/** > > + * drm_framebuffer_get_block_offset() - Get offset to start of pixel block for > > + * the given framebuffer and coordinates. > > + * @fb: The framebuffer > > + * @plane: Which plane > > + * @x: x coordinate for pixel > > + * @y: y coordinate for pixel > > + * > > + * This function will usually be called from the PLANE callback functions, > > + * or from one of the helpers that calculates the framebuffer's DMA address. > > + * > > + * Return: offset from start of framebuffer to start of pixel block > > + */ > > +u32 drm_framebuffer_get_block_offset(struct drm_framebuffer *fb, unsigned int plane, > > + unsigned int x, unsigned int y) > > Better use u64 as return type. To avoid overflow? Not sure who would use crazy large framebuffers, but doesn't hurt to play it safe. > > +{ > > + u8 h_div = 1, v_div = 1; > > + u32 block_w = drm_format_info_block_width(fb->format, plane); > > + u32 block_h = drm_format_info_block_height(fb->format, plane); > > + u32 block_size = fb->format->char_per_block[plane]; > > + u32 sample_x; > > + u32 sample_y; > > + u32 block_start_y; > > + u32 num_hblocks; > > + u32 offset; > > + > > + offset = fb->offsets[plane]; > > + > > + if (plane > 0) { > > + h_div = fb->format->hsub; > > + v_div = fb->format->vsub; > > + } > > + > > + sample_x = x / h_div; > > + sample_y = y / v_div; > > + block_start_y = (sample_y / block_h) * block_h; > > + num_hblocks = sample_x / block_w; > > + > > + offset += fb->pitches[plane] * block_start_y; > > + offset += block_size * num_hblocks; > > User space controls the values in fb->offsets and fb->pitches. I'm not > sure how well they have been validated already at this point. Did you > investigate this? It wouldn't be worse than before, since this changes is purely code movement. There are minimal sanity checks done by drm_internal_framebuffer_create() in framebuffer_check(), such as offset overflow or pitch size too small, but that's about it. It would be up to individual drivers to perform more checks that match their hardware limitations. What sort of issues are you thinking about? ChenYu > Best regards > Thomas > > > > + > > + return offset; > > +} > > +EXPORT_SYMBOL(drm_framebuffer_get_block_offset); > > + > > #ifdef CONFIG_DEBUG_FS > > static int drm_framebuffer_info(struct seq_file *m, void *data) > > { > > diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h > > index 38b24fc8978d..c07aea1cc59f 100644 > > --- a/include/drm/drm_framebuffer.h > > +++ b/include/drm/drm_framebuffer.h > > @@ -220,6 +220,9 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb); > > void drm_framebuffer_cleanup(struct drm_framebuffer *fb); > > void drm_framebuffer_unregister_private(struct drm_framebuffer *fb); > > > > +u32 drm_framebuffer_get_block_offset(struct drm_framebuffer *fb, unsigned int plane, > > + unsigned int x, unsigned int y); > > + > > /** > > * drm_framebuffer_get - acquire a framebuffer reference > > * @fb: DRM framebuffer > > -- > -- > Thomas Zimmermann > Graphics Driver Developer > SUSE Software Solutions Germany GmbH > Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com > GF: Jochen Jaser, Andrew McDonald, (HRB 36809, AG Nürnberg) > >
Hi Am 18.09.26 um 06:16 schrieb Chen-Yu Tsai: > On Thu, Sep 17, 2026 at 11:20 PM Thomas Zimmermann <tzimmermann@suse.de> wrote: >> Hi >> >> Am 16.09.26 um 05:33 schrieb Chen-Yu Tsai: >>> Currently drm_fb_dma_get_gem_addr() calculates the offset into the >>> framebuffer memory for the framebuffer's unclipped source coordinates, >>> adds that to the framebuffer's backing storage, and returns the result. >>> >>> We are about to add a variant that uses the clipped source coordinates, >>> so there is already some reuse of code. However, calculating the data >>> offset for a given pixel is not specific to the DMA FB helpers. The >>> offset is only related to the framebuffer. >>> >>> Split out the offset calculation into a new framebuffer helper so that >>> non-DMA users can also reuse the same code. >>> >>> Suggested-by: Thomas Zimmermann <tzimmermann@suse.de> >>> Cc: <stable@vger.kernel.org> # dependency for next patch >>> Signed-off-by: Chen-Yu Tsai <wenst@chromium.org> >>> --- >>> Changes since v1: >>> - New patch >>> --- >>> drivers/gpu/drm/drm_fb_dma_helper.c | 28 ++---------------- >>> drivers/gpu/drm/drm_framebuffer.c | 45 +++++++++++++++++++++++++++++ >>> include/drm/drm_framebuffer.h | 3 ++ >>> 3 files changed, 51 insertions(+), 25 deletions(-) >>> >>> diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c >>> index fd71969d2fb1..ab0f37d8a5ff 100644 >>> --- a/drivers/gpu/drm/drm_fb_dma_helper.c >>> +++ b/drivers/gpu/drm/drm_fb_dma_helper.c >>> @@ -75,36 +75,14 @@ dma_addr_t drm_fb_dma_get_gem_addr(struct drm_framebuffer *fb, >>> unsigned int plane) >>> { >>> struct drm_gem_dma_object *obj; >>> - dma_addr_t dma_addr; >>> - u8 h_div = 1, v_div = 1; >>> - u32 block_w = drm_format_info_block_width(fb->format, plane); >>> - u32 block_h = drm_format_info_block_height(fb->format, plane); >>> - u32 block_size = fb->format->char_per_block[plane]; >>> - u32 sample_x; >>> - u32 sample_y; >>> - u32 block_start_y; >>> - u32 num_hblocks; >>> >>> obj = drm_fb_dma_get_gem_obj(fb, plane); >>> if (!obj) >>> return 0; >>> >>> - dma_addr = obj->dma_addr + fb->offsets[plane]; >>> - >>> - if (plane > 0) { >>> - h_div = fb->format->hsub; >>> - v_div = fb->format->vsub; >>> - } >>> - >>> - sample_x = (state->src_x >> 16) / h_div; >>> - sample_y = (state->src_y >> 16) / v_div; >>> - block_start_y = (sample_y / block_h) * block_h; >>> - num_hblocks = sample_x / block_w; >>> - >>> - dma_addr += fb->pitches[plane] * block_start_y; >>> - dma_addr += block_size * num_hblocks; >>> - >>> - return dma_addr; >>> + return obj->dma_addr + drm_framebuffer_get_block_offset(fb, plane, >>> + state->src_x >> 16, >>> + state->src_y >> 16); >>> } >>> EXPORT_SYMBOL_GPL(drm_fb_dma_get_gem_addr); >>> >>> diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c >>> index d32aceb6ca9b..9e1231162047 100644 >>> --- a/drivers/gpu/drm/drm_framebuffer.c >>> +++ b/drivers/gpu/drm/drm_framebuffer.c >>> @@ -1208,6 +1208,51 @@ void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, >>> } >>> } >>> >>> +/** >>> + * drm_framebuffer_get_block_offset() - Get offset to start of pixel block for >>> + * the given framebuffer and coordinates. >>> + * @fb: The framebuffer >>> + * @plane: Which plane >>> + * @x: x coordinate for pixel >>> + * @y: y coordinate for pixel >>> + * >>> + * This function will usually be called from the PLANE callback functions, >>> + * or from one of the helpers that calculates the framebuffer's DMA address. >>> + * >>> + * Return: offset from start of framebuffer to start of pixel block >>> + */ >>> +u32 drm_framebuffer_get_block_offset(struct drm_framebuffer *fb, unsigned int plane, >>> + unsigned int x, unsigned int y) >> Better use u64 as return type. > To avoid overflow? Not sure who would use crazy large framebuffers, but > doesn't hurt to play it safe. I'd be worried about a malicious user space that tries to access OOB. Apart from that, we use u64 for other framebuffer-related sizes like pitch calculations or dma addresses. Using u64 here would keep that consistent. > >>> +{ >>> + u8 h_div = 1, v_div = 1; >>> + u32 block_w = drm_format_info_block_width(fb->format, plane); >>> + u32 block_h = drm_format_info_block_height(fb->format, plane); >>> + u32 block_size = fb->format->char_per_block[plane]; >>> + u32 sample_x; >>> + u32 sample_y; >>> + u32 block_start_y; >>> + u32 num_hblocks; >>> + u32 offset; >>> + >>> + offset = fb->offsets[plane]; >>> + >>> + if (plane > 0) { >>> + h_div = fb->format->hsub; >>> + v_div = fb->format->vsub; >>> + } >>> + >>> + sample_x = x / h_div; >>> + sample_y = y / v_div; >>> + block_start_y = (sample_y / block_h) * block_h; >>> + num_hblocks = sample_x / block_w; >>> + >>> + offset += fb->pitches[plane] * block_start_y; >>> + offset += block_size * num_hblocks; >> User space controls the values in fb->offsets and fb->pitches. I'm not >> sure how well they have been validated already at this point. Did you >> investigate this? > It wouldn't be worse than before, since this changes is purely code movement. > > There are minimal sanity checks done by drm_internal_framebuffer_create() > in framebuffer_check(), such as offset overflow or pitch size too small, > but that's about it. It would be up to individual drivers to perform more > checks that match their hardware limitations. Right, makes sense. Looking through the framebuffer validation, a buffer-size check could be done in framebuffer_check(). But that's another patch series. > > What sort of issues are you thinking about? Again, I'm thinking of malicious user space that crafts these values to force an OOB access. Best regards Thomas > > > ChenYu > >> Best regards >> Thomas >> >> >>> + >>> + return offset; >>> +} >>> +EXPORT_SYMBOL(drm_framebuffer_get_block_offset); >>> + >>> #ifdef CONFIG_DEBUG_FS >>> static int drm_framebuffer_info(struct seq_file *m, void *data) >>> { >>> diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h >>> index 38b24fc8978d..c07aea1cc59f 100644 >>> --- a/include/drm/drm_framebuffer.h >>> +++ b/include/drm/drm_framebuffer.h >>> @@ -220,6 +220,9 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb); >>> void drm_framebuffer_cleanup(struct drm_framebuffer *fb); >>> void drm_framebuffer_unregister_private(struct drm_framebuffer *fb); >>> >>> +u32 drm_framebuffer_get_block_offset(struct drm_framebuffer *fb, unsigned int plane, >>> + unsigned int x, unsigned int y); >>> + >>> /** >>> * drm_framebuffer_get - acquire a framebuffer reference >>> * @fb: DRM framebuffer >> -- >> -- >> Thomas Zimmermann >> Graphics Driver Developer >> SUSE Software Solutions Germany GmbH >> Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com >> GF: Jochen Jaser, Andrew McDonald, (HRB 36809, AG Nürnberg) >> >>
On Fri, Sep 18, 2026 at 2:41 PM Thomas Zimmermann <tzimmermann@suse.de> wrote: > > Hi > > Am 18.09.26 um 06:16 schrieb Chen-Yu Tsai: > > On Thu, Sep 17, 2026 at 11:20 PM Thomas Zimmermann <tzimmermann@suse.de> wrote: > >> Hi > >> > >> Am 16.09.26 um 05:33 schrieb Chen-Yu Tsai: > >>> Currently drm_fb_dma_get_gem_addr() calculates the offset into the > >>> framebuffer memory for the framebuffer's unclipped source coordinates, > >>> adds that to the framebuffer's backing storage, and returns the result. > >>> > >>> We are about to add a variant that uses the clipped source coordinates, > >>> so there is already some reuse of code. However, calculating the data > >>> offset for a given pixel is not specific to the DMA FB helpers. The > >>> offset is only related to the framebuffer. > >>> > >>> Split out the offset calculation into a new framebuffer helper so that > >>> non-DMA users can also reuse the same code. > >>> > >>> Suggested-by: Thomas Zimmermann <tzimmermann@suse.de> > >>> Cc: <stable@vger.kernel.org> # dependency for next patch > >>> Signed-off-by: Chen-Yu Tsai <wenst@chromium.org> > >>> --- > >>> Changes since v1: > >>> - New patch > >>> --- > >>> drivers/gpu/drm/drm_fb_dma_helper.c | 28 ++---------------- > >>> drivers/gpu/drm/drm_framebuffer.c | 45 +++++++++++++++++++++++++++++ > >>> include/drm/drm_framebuffer.h | 3 ++ > >>> 3 files changed, 51 insertions(+), 25 deletions(-) > >>> > >>> diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c > >>> index fd71969d2fb1..ab0f37d8a5ff 100644 > >>> --- a/drivers/gpu/drm/drm_fb_dma_helper.c > >>> +++ b/drivers/gpu/drm/drm_fb_dma_helper.c > >>> @@ -75,36 +75,14 @@ dma_addr_t drm_fb_dma_get_gem_addr(struct drm_framebuffer *fb, > >>> unsigned int plane) > >>> { > >>> struct drm_gem_dma_object *obj; > >>> - dma_addr_t dma_addr; > >>> - u8 h_div = 1, v_div = 1; > >>> - u32 block_w = drm_format_info_block_width(fb->format, plane); > >>> - u32 block_h = drm_format_info_block_height(fb->format, plane); > >>> - u32 block_size = fb->format->char_per_block[plane]; > >>> - u32 sample_x; > >>> - u32 sample_y; > >>> - u32 block_start_y; > >>> - u32 num_hblocks; > >>> > >>> obj = drm_fb_dma_get_gem_obj(fb, plane); > >>> if (!obj) > >>> return 0; > >>> > >>> - dma_addr = obj->dma_addr + fb->offsets[plane]; > >>> - > >>> - if (plane > 0) { > >>> - h_div = fb->format->hsub; > >>> - v_div = fb->format->vsub; > >>> - } > >>> - > >>> - sample_x = (state->src_x >> 16) / h_div; > >>> - sample_y = (state->src_y >> 16) / v_div; > >>> - block_start_y = (sample_y / block_h) * block_h; > >>> - num_hblocks = sample_x / block_w; > >>> - > >>> - dma_addr += fb->pitches[plane] * block_start_y; > >>> - dma_addr += block_size * num_hblocks; > >>> - > >>> - return dma_addr; > >>> + return obj->dma_addr + drm_framebuffer_get_block_offset(fb, plane, > >>> + state->src_x >> 16, > >>> + state->src_y >> 16); > >>> } > >>> EXPORT_SYMBOL_GPL(drm_fb_dma_get_gem_addr); > >>> > >>> diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c > >>> index d32aceb6ca9b..9e1231162047 100644 > >>> --- a/drivers/gpu/drm/drm_framebuffer.c > >>> +++ b/drivers/gpu/drm/drm_framebuffer.c > >>> @@ -1208,6 +1208,51 @@ void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, > >>> } > >>> } > >>> > >>> +/** > >>> + * drm_framebuffer_get_block_offset() - Get offset to start of pixel block for > >>> + * the given framebuffer and coordinates. > >>> + * @fb: The framebuffer > >>> + * @plane: Which plane > >>> + * @x: x coordinate for pixel > >>> + * @y: y coordinate for pixel > >>> + * > >>> + * This function will usually be called from the PLANE callback functions, > >>> + * or from one of the helpers that calculates the framebuffer's DMA address. > >>> + * > >>> + * Return: offset from start of framebuffer to start of pixel block > >>> + */ > >>> +u32 drm_framebuffer_get_block_offset(struct drm_framebuffer *fb, unsigned int plane, > >>> + unsigned int x, unsigned int y) > >> Better use u64 as return type. > > To avoid overflow? Not sure who would use crazy large framebuffers, but > > doesn't hurt to play it safe. > > I'd be worried about a malicious user space that tries to access OOB. > > Apart from that, we use u64 for other framebuffer-related sizes like > pitch calculations or dma addresses. Using u64 here would keep that > consistent. Indeed. It seemed weird that the helper originally used u32. Maybe it was carried over from CMA on ARMv7, which predominantly only had 32-bit address space data busses? > > > > >>> +{ > >>> + u8 h_div = 1, v_div = 1; > >>> + u32 block_w = drm_format_info_block_width(fb->format, plane); > >>> + u32 block_h = drm_format_info_block_height(fb->format, plane); > >>> + u32 block_size = fb->format->char_per_block[plane]; > >>> + u32 sample_x; > >>> + u32 sample_y; > >>> + u32 block_start_y; > >>> + u32 num_hblocks; > >>> + u32 offset; > >>> + > >>> + offset = fb->offsets[plane]; > >>> + > >>> + if (plane > 0) { > >>> + h_div = fb->format->hsub; > >>> + v_div = fb->format->vsub; > >>> + } > >>> + > >>> + sample_x = x / h_div; > >>> + sample_y = y / v_div; > >>> + block_start_y = (sample_y / block_h) * block_h; > >>> + num_hblocks = sample_x / block_w; > >>> + > >>> + offset += fb->pitches[plane] * block_start_y; > >>> + offset += block_size * num_hblocks; > >> User space controls the values in fb->offsets and fb->pitches. I'm not > >> sure how well they have been validated already at this point. Did you > >> investigate this? > > It wouldn't be worse than before, since this changes is purely code movement. > > > > There are minimal sanity checks done by drm_internal_framebuffer_create() > > in framebuffer_check(), such as offset overflow or pitch size too small, > > but that's about it. It would be up to individual drivers to perform more > > checks that match their hardware limitations. > > Right, makes sense. Looking through the framebuffer validation, a > buffer-size check could be done in framebuffer_check(). But that's > another patch series. That's further covered by drm_gem_fb_init_with_funcs(), which drm_gem_fb_create*() goes into. I didn't check all the drivers that implemented their own .fb_create callback though. - rockchip uses the GEM FB helpers - MSM reimplements the GEM FB helpers, but does have proper size checks - nouveau has size checks - omap has size checks > > > > What sort of issues are you thinking about? > > Again, I'm thinking of malicious user space that crafts these values to > force an OOB access. I think we're covered. Thanks ChenYu > Best regards > Thomas > > > > > > > > ChenYu > > > >> Best regards > >> Thomas > >> > >> > >>> + > >>> + return offset; > >>> +} > >>> +EXPORT_SYMBOL(drm_framebuffer_get_block_offset); > >>> + > >>> #ifdef CONFIG_DEBUG_FS > >>> static int drm_framebuffer_info(struct seq_file *m, void *data) > >>> { > >>> diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h > >>> index 38b24fc8978d..c07aea1cc59f 100644 > >>> --- a/include/drm/drm_framebuffer.h > >>> +++ b/include/drm/drm_framebuffer.h > >>> @@ -220,6 +220,9 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb); > >>> void drm_framebuffer_cleanup(struct drm_framebuffer *fb); > >>> void drm_framebuffer_unregister_private(struct drm_framebuffer *fb); > >>> > >>> +u32 drm_framebuffer_get_block_offset(struct drm_framebuffer *fb, unsigned int plane, > >>> + unsigned int x, unsigned int y); > >>> + > >>> /** > >>> * drm_framebuffer_get - acquire a framebuffer reference > >>> * @fb: DRM framebuffer > >> -- > >> -- > >> Thomas Zimmermann > >> Graphics Driver Developer > >> SUSE Software Solutions Germany GmbH > >> Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com > >> GF: Jochen Jaser, Andrew McDonald, (HRB 36809, AG Nürnberg) > >> > >> > > -- > -- > Thomas Zimmermann > Graphics Driver Developer > SUSE Software Solutions Germany GmbH > Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com > GF: Jochen Jaser, Andrew McDonald, (HRB 36809, AG Nürnberg) > >
On Fri, Sep 18, 2026 at 3:06 PM Chen-Yu Tsai <wenst@chromium.org> wrote: > > On Fri, Sep 18, 2026 at 2:41 PM Thomas Zimmermann <tzimmermann@suse.de> wrote: > > > > Hi > > > > Am 18.09.26 um 06:16 schrieb Chen-Yu Tsai: > > > On Thu, Sep 17, 2026 at 11:20 PM Thomas Zimmermann <tzimmermann@suse.de> wrote: > > >> Hi > > >> > > >> Am 16.09.26 um 05:33 schrieb Chen-Yu Tsai: > > >>> Currently drm_fb_dma_get_gem_addr() calculates the offset into the > > >>> framebuffer memory for the framebuffer's unclipped source coordinates, > > >>> adds that to the framebuffer's backing storage, and returns the result. > > >>> > > >>> We are about to add a variant that uses the clipped source coordinates, > > >>> so there is already some reuse of code. However, calculating the data > > >>> offset for a given pixel is not specific to the DMA FB helpers. The > > >>> offset is only related to the framebuffer. > > >>> > > >>> Split out the offset calculation into a new framebuffer helper so that > > >>> non-DMA users can also reuse the same code. > > >>> > > >>> Suggested-by: Thomas Zimmermann <tzimmermann@suse.de> > > >>> Cc: <stable@vger.kernel.org> # dependency for next patch > > >>> Signed-off-by: Chen-Yu Tsai <wenst@chromium.org> > > >>> --- > > >>> Changes since v1: > > >>> - New patch > > >>> --- > > >>> drivers/gpu/drm/drm_fb_dma_helper.c | 28 ++---------------- > > >>> drivers/gpu/drm/drm_framebuffer.c | 45 +++++++++++++++++++++++++++++ > > >>> include/drm/drm_framebuffer.h | 3 ++ > > >>> 3 files changed, 51 insertions(+), 25 deletions(-) > > >>> > > >>> diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c > > >>> index fd71969d2fb1..ab0f37d8a5ff 100644 > > >>> --- a/drivers/gpu/drm/drm_fb_dma_helper.c > > >>> +++ b/drivers/gpu/drm/drm_fb_dma_helper.c > > >>> @@ -75,36 +75,14 @@ dma_addr_t drm_fb_dma_get_gem_addr(struct drm_framebuffer *fb, > > >>> unsigned int plane) > > >>> { > > >>> struct drm_gem_dma_object *obj; > > >>> - dma_addr_t dma_addr; > > >>> - u8 h_div = 1, v_div = 1; > > >>> - u32 block_w = drm_format_info_block_width(fb->format, plane); > > >>> - u32 block_h = drm_format_info_block_height(fb->format, plane); > > >>> - u32 block_size = fb->format->char_per_block[plane]; > > >>> - u32 sample_x; > > >>> - u32 sample_y; > > >>> - u32 block_start_y; > > >>> - u32 num_hblocks; > > >>> > > >>> obj = drm_fb_dma_get_gem_obj(fb, plane); > > >>> if (!obj) > > >>> return 0; > > >>> > > >>> - dma_addr = obj->dma_addr + fb->offsets[plane]; > > >>> - > > >>> - if (plane > 0) { > > >>> - h_div = fb->format->hsub; > > >>> - v_div = fb->format->vsub; > > >>> - } > > >>> - > > >>> - sample_x = (state->src_x >> 16) / h_div; > > >>> - sample_y = (state->src_y >> 16) / v_div; > > >>> - block_start_y = (sample_y / block_h) * block_h; > > >>> - num_hblocks = sample_x / block_w; > > >>> - > > >>> - dma_addr += fb->pitches[plane] * block_start_y; > > >>> - dma_addr += block_size * num_hblocks; > > >>> - > > >>> - return dma_addr; > > >>> + return obj->dma_addr + drm_framebuffer_get_block_offset(fb, plane, > > >>> + state->src_x >> 16, > > >>> + state->src_y >> 16); > > >>> } > > >>> EXPORT_SYMBOL_GPL(drm_fb_dma_get_gem_addr); > > >>> > > >>> diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c > > >>> index d32aceb6ca9b..9e1231162047 100644 > > >>> --- a/drivers/gpu/drm/drm_framebuffer.c > > >>> +++ b/drivers/gpu/drm/drm_framebuffer.c > > >>> @@ -1208,6 +1208,51 @@ void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, > > >>> } > > >>> } > > >>> > > >>> +/** > > >>> + * drm_framebuffer_get_block_offset() - Get offset to start of pixel block for > > >>> + * the given framebuffer and coordinates. > > >>> + * @fb: The framebuffer > > >>> + * @plane: Which plane > > >>> + * @x: x coordinate for pixel > > >>> + * @y: y coordinate for pixel > > >>> + * > > >>> + * This function will usually be called from the PLANE callback functions, > > >>> + * or from one of the helpers that calculates the framebuffer's DMA address. > > >>> + * > > >>> + * Return: offset from start of framebuffer to start of pixel block > > >>> + */ > > >>> +u32 drm_framebuffer_get_block_offset(struct drm_framebuffer *fb, unsigned int plane, > > >>> + unsigned int x, unsigned int y) > > >> Better use u64 as return type. > > > To avoid overflow? Not sure who would use crazy large framebuffers, but > > > doesn't hurt to play it safe. > > > > I'd be worried about a malicious user space that tries to access OOB. > > > > Apart from that, we use u64 for other framebuffer-related sizes like > > pitch calculations or dma addresses. Using u64 here would keep that > > consistent. > > Indeed. It seemed weird that the helper originally used u32. Maybe it > was carried over from CMA on ARMv7, which predominantly only had > 32-bit address space data busses? > > > > > > > > >>> +{ > > >>> + u8 h_div = 1, v_div = 1; > > >>> + u32 block_w = drm_format_info_block_width(fb->format, plane); > > >>> + u32 block_h = drm_format_info_block_height(fb->format, plane); > > >>> + u32 block_size = fb->format->char_per_block[plane]; > > >>> + u32 sample_x; > > >>> + u32 sample_y; > > >>> + u32 block_start_y; > > >>> + u32 num_hblocks; > > >>> + u32 offset; > > >>> + > > >>> + offset = fb->offsets[plane]; > > >>> + > > >>> + if (plane > 0) { > > >>> + h_div = fb->format->hsub; > > >>> + v_div = fb->format->vsub; > > >>> + } > > >>> + > > >>> + sample_x = x / h_div; > > >>> + sample_y = y / v_div; > > >>> + block_start_y = (sample_y / block_h) * block_h; > > >>> + num_hblocks = sample_x / block_w; > > >>> + > > >>> + offset += fb->pitches[plane] * block_start_y; > > >>> + offset += block_size * num_hblocks; > > >> User space controls the values in fb->offsets and fb->pitches. I'm not > > >> sure how well they have been validated already at this point. Did you > > >> investigate this? > > > It wouldn't be worse than before, since this changes is purely code movement. > > > > > > There are minimal sanity checks done by drm_internal_framebuffer_create() > > > in framebuffer_check(), such as offset overflow or pitch size too small, > > > but that's about it. It would be up to individual drivers to perform more > > > checks that match their hardware limitations. > > > > Right, makes sense. Looking through the framebuffer validation, a > > buffer-size check could be done in framebuffer_check(). But that's > > another patch series. > > That's further covered by drm_gem_fb_init_with_funcs(), which > drm_gem_fb_create*() goes into. I didn't check all the drivers that > implemented their own .fb_create callback though. > > - rockchip uses the GEM FB helpers > - MSM reimplements the GEM FB helpers, but does have proper size checks > - nouveau has size checks > - omap has size checks Side note: it seems that the drivers that reimplement drm_gem_fb_init_with_funcs() do so because they need to do additional checks on the (sub-classed) GEM objects. Perhaps exporting drm_gem_fb_init() or deconstructing drm_gem_fb_init_with_funcs() could allow more of them to use common helpers for things like size checks. > > > > > > What sort of issues are you thinking about? > > > > Again, I'm thinking of malicious user space that crafts these values to > > force an OOB access. > > I think we're covered. > > > Thanks > ChenYu > > > Best regards > > Thomas > > > > > > > > > > > > > ChenYu > > > > > >> Best regards > > >> Thomas > > >> > > >> > > >>> + > > >>> + return offset; > > >>> +} > > >>> +EXPORT_SYMBOL(drm_framebuffer_get_block_offset); > > >>> + > > >>> #ifdef CONFIG_DEBUG_FS > > >>> static int drm_framebuffer_info(struct seq_file *m, void *data) > > >>> { > > >>> diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h > > >>> index 38b24fc8978d..c07aea1cc59f 100644 > > >>> --- a/include/drm/drm_framebuffer.h > > >>> +++ b/include/drm/drm_framebuffer.h > > >>> @@ -220,6 +220,9 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb); > > >>> void drm_framebuffer_cleanup(struct drm_framebuffer *fb); > > >>> void drm_framebuffer_unregister_private(struct drm_framebuffer *fb); > > >>> > > >>> +u32 drm_framebuffer_get_block_offset(struct drm_framebuffer *fb, unsigned int plane, > > >>> + unsigned int x, unsigned int y); > > >>> + > > >>> /** > > >>> * drm_framebuffer_get - acquire a framebuffer reference > > >>> * @fb: DRM framebuffer > > >> -- > > >> -- > > >> Thomas Zimmermann > > >> Graphics Driver Developer > > >> SUSE Software Solutions Germany GmbH > > >> Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com > > >> GF: Jochen Jaser, Andrew McDonald, (HRB 36809, AG Nürnberg) > > >> > > >> > > > > -- > > -- > > Thomas Zimmermann > > Graphics Driver Developer > > SUSE Software Solutions Germany GmbH > > Frankenstr. 146, 90461 Nürnberg, Germany, www.suse.com > > GF: Jochen Jaser, Andrew McDonald, (HRB 36809, AG Nürnberg) > > > >
diff --git a/drivers/gpu/drm/drm_fb_dma_helper.c b/drivers/gpu/drm/drm_fb_dma_helper.c index fd71969d2fb1..ab0f37d8a5ff 100644 --- a/drivers/gpu/drm/drm_fb_dma_helper.c +++ b/drivers/gpu/drm/drm_fb_dma_helper.c @@ -75,36 +75,14 @@ dma_addr_t drm_fb_dma_get_gem_addr(struct drm_framebuffer *fb, unsigned int plane) { struct drm_gem_dma_object *obj; - dma_addr_t dma_addr; - u8 h_div = 1, v_div = 1; - u32 block_w = drm_format_info_block_width(fb->format, plane); - u32 block_h = drm_format_info_block_height(fb->format, plane); - u32 block_size = fb->format->char_per_block[plane]; - u32 sample_x; - u32 sample_y; - u32 block_start_y; - u32 num_hblocks; obj = drm_fb_dma_get_gem_obj(fb, plane); if (!obj) return 0; - dma_addr = obj->dma_addr + fb->offsets[plane]; - - if (plane > 0) { - h_div = fb->format->hsub; - v_div = fb->format->vsub; - } - - sample_x = (state->src_x >> 16) / h_div; - sample_y = (state->src_y >> 16) / v_div; - block_start_y = (sample_y / block_h) * block_h; - num_hblocks = sample_x / block_w; - - dma_addr += fb->pitches[plane] * block_start_y; - dma_addr += block_size * num_hblocks; - - return dma_addr; + return obj->dma_addr + drm_framebuffer_get_block_offset(fb, plane, + state->src_x >> 16, + state->src_y >> 16); } EXPORT_SYMBOL_GPL(drm_fb_dma_get_gem_addr); diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index d32aceb6ca9b..9e1231162047 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -1208,6 +1208,51 @@ void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, } } +/** + * drm_framebuffer_get_block_offset() - Get offset to start of pixel block for + * the given framebuffer and coordinates. + * @fb: The framebuffer + * @plane: Which plane + * @x: x coordinate for pixel + * @y: y coordinate for pixel + * + * This function will usually be called from the PLANE callback functions, + * or from one of the helpers that calculates the framebuffer's DMA address. + * + * Return: offset from start of framebuffer to start of pixel block + */ +u32 drm_framebuffer_get_block_offset(struct drm_framebuffer *fb, unsigned int plane, + unsigned int x, unsigned int y) +{ + u8 h_div = 1, v_div = 1; + u32 block_w = drm_format_info_block_width(fb->format, plane); + u32 block_h = drm_format_info_block_height(fb->format, plane); + u32 block_size = fb->format->char_per_block[plane]; + u32 sample_x; + u32 sample_y; + u32 block_start_y; + u32 num_hblocks; + u32 offset; + + offset = fb->offsets[plane]; + + if (plane > 0) { + h_div = fb->format->hsub; + v_div = fb->format->vsub; + } + + sample_x = x / h_div; + sample_y = y / v_div; + block_start_y = (sample_y / block_h) * block_h; + num_hblocks = sample_x / block_w; + + offset += fb->pitches[plane] * block_start_y; + offset += block_size * num_hblocks; + + return offset; +} +EXPORT_SYMBOL(drm_framebuffer_get_block_offset); + #ifdef CONFIG_DEBUG_FS static int drm_framebuffer_info(struct seq_file *m, void *data) { diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index 38b24fc8978d..c07aea1cc59f 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h @@ -220,6 +220,9 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb); void drm_framebuffer_cleanup(struct drm_framebuffer *fb); void drm_framebuffer_unregister_private(struct drm_framebuffer *fb); +u32 drm_framebuffer_get_block_offset(struct drm_framebuffer *fb, unsigned int plane, + unsigned int x, unsigned int y); + /** * drm_framebuffer_get - acquire a framebuffer reference * @fb: DRM framebuffer