2005-11-09 13:39:12 +08:00
|
|
|
/*
|
|
|
|
* linux/drivers/video/console/fbcon_ud.c -- Software Rotation - 90 degrees
|
|
|
|
*
|
|
|
|
* Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
|
|
|
|
*
|
|
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
|
|
* License. See the file COPYING in the main directory of this archive for
|
|
|
|
* more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/module.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
|
|
|
#include <linux/slab.h>
|
2005-11-09 13:39:12 +08:00
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/fb.h>
|
|
|
|
#include <linux/vt_kern.h>
|
|
|
|
#include <linux/console.h>
|
|
|
|
#include <asm/types.h>
|
|
|
|
#include "fbcon.h"
|
|
|
|
#include "fbcon_rotate.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Rotation 90 degrees
|
|
|
|
*/
|
|
|
|
|
2010-08-11 09:02:29 +08:00
|
|
|
static void cw_update_attr(u8 *dst, u8 *src, int attribute,
|
2005-11-09 13:39:12 +08:00
|
|
|
struct vc_data *vc)
|
|
|
|
{
|
|
|
|
int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;
|
|
|
|
int width = (vc->vc_font.height + 7) >> 3;
|
2013-04-30 06:05:31 +08:00
|
|
|
u8 c, msk = ~(0xff >> offset);
|
2005-11-09 13:39:12 +08:00
|
|
|
|
|
|
|
for (i = 0; i < vc->vc_font.width; i++) {
|
|
|
|
for (j = 0; j < width; j++) {
|
|
|
|
c = *src;
|
|
|
|
if (attribute & FBCON_ATTRIBUTE_UNDERLINE && !j)
|
|
|
|
c |= msk;
|
|
|
|
if (attribute & FBCON_ATTRIBUTE_BOLD && i)
|
|
|
|
c |= *(src-width);
|
|
|
|
if (attribute & FBCON_ATTRIBUTE_REVERSE)
|
|
|
|
c = ~c;
|
|
|
|
src++;
|
|
|
|
*dst++ = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Revert "fbdev: Garbage collect fbdev scrolling acceleration, part 1 (from TODO list)"
This reverts commit b3ec8cdf457e5e63d396fe1346cc788cf7c1b578.
Revert the second (of 2) commits which disabled scrolling acceleration
in fbcon/fbdev. It introduced a regression for fbdev-supported graphic
cards because of the performance penalty by doing screen scrolling by
software instead of using the existing graphic card 2D hardware
acceleration.
Console scrolling acceleration was disabled by dropping code which
checked at runtime the driver hardware capabilities for the
BINFO_HWACCEL_COPYAREA or FBINFO_HWACCEL_FILLRECT flags and if set, it
enabled scrollmode SCROLL_MOVE which uses hardware acceleration to move
screen contents. After dropping those checks scrollmode was hard-wired
to SCROLL_REDRAW instead, which forces all graphic cards to redraw every
character at the new screen position when scrolling.
This change effectively disabled all hardware-based scrolling acceleration for
ALL drivers, because now all kind of 2D hardware acceleration (bitblt,
fillrect) in the drivers isn't used any longer.
The original commit message mentions that only 3 DRM drivers (nouveau, omapdrm
and gma500) used hardware acceleration in the past and thus code for checking
and using scrolling acceleration is obsolete.
This statement is NOT TRUE, because beside the DRM drivers there are around 35
other fbdev drivers which depend on fbdev/fbcon and still provide hardware
acceleration for fbdev/fbcon.
The original commit message also states that syzbot found lots of bugs in fbcon
and thus it's "often the solution to just delete code and remove features".
This is true, and the bugs - which actually affected all users of fbcon,
including DRM - were fixed, or code was dropped like e.g. the support for
software scrollback in vgacon (commit 973c096f6a85).
So to further analyze which bugs were found by syzbot, I've looked through all
patches in drivers/video which were tagged with syzbot or syzkaller back to
year 2005. The vast majority fixed the reported issues on a higher level, e.g.
when screen is to be resized, or when font size is to be changed. The few ones
which touched driver code fixed a real driver bug, e.g. by adding a check.
But NONE of those patches touched code of either the SCROLL_MOVE or the
SCROLL_REDRAW case.
That means, there was no real reason why SCROLL_MOVE had to be ripped-out and
just SCROLL_REDRAW had to be used instead. The only reason I can imagine so far
was that SCROLL_MOVE wasn't used by DRM and as such it was assumed that it
could go away. That argument completely missed the fact that SCROLL_MOVE is
still heavily used by fbdev (non-DRM) drivers.
Some people mention that using memcpy() instead of the hardware acceleration is
pretty much the same speed. But that's not true, at least not for older graphic
cards and machines where we see speed decreases by factor 10 and more and thus
this change leads to console responsiveness way worse than before.
That's why the original commit is to be reverted. By reverting we
reintroduce hardware-based scrolling acceleration and fix the
performance regression for fbdev drivers.
There isn't any impact on DRM when reverting those patches.
Signed-off-by: Helge Deller <deller@gmx.de>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Sven Schnelle <svens@stackframe.org>
Cc: stable@vger.kernel.org # v5.16+
Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20220202135531.92183-2-deller@gmx.de
2022-02-02 21:55:29 +08:00
|
|
|
|
|
|
|
static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
|
|
|
|
int sx, int dy, int dx, int height, int width)
|
|
|
|
{
|
|
|
|
struct fbcon_ops *ops = info->fbcon_par;
|
|
|
|
struct fb_copyarea area;
|
2022-02-02 21:55:31 +08:00
|
|
|
u32 vxres = GETVXRES(ops->p, info);
|
Revert "fbdev: Garbage collect fbdev scrolling acceleration, part 1 (from TODO list)"
This reverts commit b3ec8cdf457e5e63d396fe1346cc788cf7c1b578.
Revert the second (of 2) commits which disabled scrolling acceleration
in fbcon/fbdev. It introduced a regression for fbdev-supported graphic
cards because of the performance penalty by doing screen scrolling by
software instead of using the existing graphic card 2D hardware
acceleration.
Console scrolling acceleration was disabled by dropping code which
checked at runtime the driver hardware capabilities for the
BINFO_HWACCEL_COPYAREA or FBINFO_HWACCEL_FILLRECT flags and if set, it
enabled scrollmode SCROLL_MOVE which uses hardware acceleration to move
screen contents. After dropping those checks scrollmode was hard-wired
to SCROLL_REDRAW instead, which forces all graphic cards to redraw every
character at the new screen position when scrolling.
This change effectively disabled all hardware-based scrolling acceleration for
ALL drivers, because now all kind of 2D hardware acceleration (bitblt,
fillrect) in the drivers isn't used any longer.
The original commit message mentions that only 3 DRM drivers (nouveau, omapdrm
and gma500) used hardware acceleration in the past and thus code for checking
and using scrolling acceleration is obsolete.
This statement is NOT TRUE, because beside the DRM drivers there are around 35
other fbdev drivers which depend on fbdev/fbcon and still provide hardware
acceleration for fbdev/fbcon.
The original commit message also states that syzbot found lots of bugs in fbcon
and thus it's "often the solution to just delete code and remove features".
This is true, and the bugs - which actually affected all users of fbcon,
including DRM - were fixed, or code was dropped like e.g. the support for
software scrollback in vgacon (commit 973c096f6a85).
So to further analyze which bugs were found by syzbot, I've looked through all
patches in drivers/video which were tagged with syzbot or syzkaller back to
year 2005. The vast majority fixed the reported issues on a higher level, e.g.
when screen is to be resized, or when font size is to be changed. The few ones
which touched driver code fixed a real driver bug, e.g. by adding a check.
But NONE of those patches touched code of either the SCROLL_MOVE or the
SCROLL_REDRAW case.
That means, there was no real reason why SCROLL_MOVE had to be ripped-out and
just SCROLL_REDRAW had to be used instead. The only reason I can imagine so far
was that SCROLL_MOVE wasn't used by DRM and as such it was assumed that it
could go away. That argument completely missed the fact that SCROLL_MOVE is
still heavily used by fbdev (non-DRM) drivers.
Some people mention that using memcpy() instead of the hardware acceleration is
pretty much the same speed. But that's not true, at least not for older graphic
cards and machines where we see speed decreases by factor 10 and more and thus
this change leads to console responsiveness way worse than before.
That's why the original commit is to be reverted. By reverting we
reintroduce hardware-based scrolling acceleration and fix the
performance regression for fbdev drivers.
There isn't any impact on DRM when reverting those patches.
Signed-off-by: Helge Deller <deller@gmx.de>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Sven Schnelle <svens@stackframe.org>
Cc: stable@vger.kernel.org # v5.16+
Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20220202135531.92183-2-deller@gmx.de
2022-02-02 21:55:29 +08:00
|
|
|
|
|
|
|
area.sx = vxres - ((sy + height) * vc->vc_font.height);
|
|
|
|
area.sy = sx * vc->vc_font.width;
|
|
|
|
area.dx = vxres - ((dy + height) * vc->vc_font.height);
|
|
|
|
area.dy = dx * vc->vc_font.width;
|
|
|
|
area.width = height * vc->vc_font.height;
|
|
|
|
area.height = width * vc->vc_font.width;
|
|
|
|
|
|
|
|
info->fbops->fb_copyarea(info, &area);
|
|
|
|
}
|
|
|
|
|
2005-11-09 13:39:12 +08:00
|
|
|
static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
|
|
|
|
int sx, int height, int width)
|
|
|
|
{
|
Revert "fbdev: Garbage collect fbdev scrolling acceleration, part 1 (from TODO list)"
This reverts commit b3ec8cdf457e5e63d396fe1346cc788cf7c1b578.
Revert the second (of 2) commits which disabled scrolling acceleration
in fbcon/fbdev. It introduced a regression for fbdev-supported graphic
cards because of the performance penalty by doing screen scrolling by
software instead of using the existing graphic card 2D hardware
acceleration.
Console scrolling acceleration was disabled by dropping code which
checked at runtime the driver hardware capabilities for the
BINFO_HWACCEL_COPYAREA or FBINFO_HWACCEL_FILLRECT flags and if set, it
enabled scrollmode SCROLL_MOVE which uses hardware acceleration to move
screen contents. After dropping those checks scrollmode was hard-wired
to SCROLL_REDRAW instead, which forces all graphic cards to redraw every
character at the new screen position when scrolling.
This change effectively disabled all hardware-based scrolling acceleration for
ALL drivers, because now all kind of 2D hardware acceleration (bitblt,
fillrect) in the drivers isn't used any longer.
The original commit message mentions that only 3 DRM drivers (nouveau, omapdrm
and gma500) used hardware acceleration in the past and thus code for checking
and using scrolling acceleration is obsolete.
This statement is NOT TRUE, because beside the DRM drivers there are around 35
other fbdev drivers which depend on fbdev/fbcon and still provide hardware
acceleration for fbdev/fbcon.
The original commit message also states that syzbot found lots of bugs in fbcon
and thus it's "often the solution to just delete code and remove features".
This is true, and the bugs - which actually affected all users of fbcon,
including DRM - were fixed, or code was dropped like e.g. the support for
software scrollback in vgacon (commit 973c096f6a85).
So to further analyze which bugs were found by syzbot, I've looked through all
patches in drivers/video which were tagged with syzbot or syzkaller back to
year 2005. The vast majority fixed the reported issues on a higher level, e.g.
when screen is to be resized, or when font size is to be changed. The few ones
which touched driver code fixed a real driver bug, e.g. by adding a check.
But NONE of those patches touched code of either the SCROLL_MOVE or the
SCROLL_REDRAW case.
That means, there was no real reason why SCROLL_MOVE had to be ripped-out and
just SCROLL_REDRAW had to be used instead. The only reason I can imagine so far
was that SCROLL_MOVE wasn't used by DRM and as such it was assumed that it
could go away. That argument completely missed the fact that SCROLL_MOVE is
still heavily used by fbdev (non-DRM) drivers.
Some people mention that using memcpy() instead of the hardware acceleration is
pretty much the same speed. But that's not true, at least not for older graphic
cards and machines where we see speed decreases by factor 10 and more and thus
this change leads to console responsiveness way worse than before.
That's why the original commit is to be reverted. By reverting we
reintroduce hardware-based scrolling acceleration and fix the
performance regression for fbdev drivers.
There isn't any impact on DRM when reverting those patches.
Signed-off-by: Helge Deller <deller@gmx.de>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Sven Schnelle <svens@stackframe.org>
Cc: stable@vger.kernel.org # v5.16+
Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20220202135531.92183-2-deller@gmx.de
2022-02-02 21:55:29 +08:00
|
|
|
struct fbcon_ops *ops = info->fbcon_par;
|
2005-11-09 13:39:12 +08:00
|
|
|
struct fb_fillrect region;
|
|
|
|
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
|
2022-02-02 21:55:31 +08:00
|
|
|
u32 vxres = GETVXRES(ops->p, info);
|
2005-11-09 13:39:12 +08:00
|
|
|
|
2008-02-06 17:39:45 +08:00
|
|
|
region.color = attr_bgcol_ec(bgshift,vc,info);
|
2005-11-09 13:39:12 +08:00
|
|
|
region.dx = vxres - ((sy + height) * vc->vc_font.height);
|
|
|
|
region.dy = sx * vc->vc_font.width;
|
|
|
|
region.height = width * vc->vc_font.width;
|
|
|
|
region.width = height * vc->vc_font.height;
|
|
|
|
region.rop = ROP_COPY;
|
|
|
|
|
|
|
|
info->fbops->fb_fillrect(info, ®ion);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
|
|
|
|
const u16 *s, u32 attr, u32 cnt,
|
|
|
|
u32 d_pitch, u32 s_pitch, u32 cellsize,
|
|
|
|
struct fb_image *image, u8 *buf, u8 *dst)
|
|
|
|
{
|
|
|
|
struct fbcon_ops *ops = info->fbcon_par;
|
|
|
|
u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
|
|
|
|
u32 idx = (vc->vc_font.height + 7) >> 3;
|
|
|
|
u8 *src;
|
|
|
|
|
|
|
|
while (cnt--) {
|
|
|
|
src = ops->fontbuffer + (scr_readw(s++) & charmask)*cellsize;
|
|
|
|
|
|
|
|
if (attr) {
|
|
|
|
cw_update_attr(buf, src, attr, vc);
|
|
|
|
src = buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (likely(idx == 1))
|
|
|
|
__fb_pad_aligned_buffer(dst, d_pitch, src, idx,
|
|
|
|
vc->vc_font.width);
|
|
|
|
else
|
|
|
|
fb_pad_aligned_buffer(dst, d_pitch, src, idx,
|
|
|
|
vc->vc_font.width);
|
|
|
|
|
|
|
|
dst += d_pitch * vc->vc_font.width;
|
|
|
|
}
|
|
|
|
|
|
|
|
info->fbops->fb_imageblit(info, image);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cw_putcs(struct vc_data *vc, struct fb_info *info,
|
|
|
|
const unsigned short *s, int count, int yy, int xx,
|
|
|
|
int fg, int bg)
|
|
|
|
{
|
|
|
|
struct fb_image image;
|
|
|
|
struct fbcon_ops *ops = info->fbcon_par;
|
|
|
|
u32 width = (vc->vc_font.height + 7)/8;
|
|
|
|
u32 cellsize = width * vc->vc_font.width;
|
|
|
|
u32 maxcnt = info->pixmap.size/cellsize;
|
|
|
|
u32 scan_align = info->pixmap.scan_align - 1;
|
|
|
|
u32 buf_align = info->pixmap.buf_align - 1;
|
|
|
|
u32 cnt, pitch, size;
|
|
|
|
u32 attribute = get_attribute(info, scr_readw(s));
|
|
|
|
u8 *dst, *buf = NULL;
|
2022-02-02 21:55:31 +08:00
|
|
|
u32 vxres = GETVXRES(ops->p, info);
|
2005-11-09 13:39:12 +08:00
|
|
|
|
|
|
|
if (!ops->fontbuffer)
|
|
|
|
return;
|
|
|
|
|
|
|
|
image.fg_color = fg;
|
|
|
|
image.bg_color = bg;
|
|
|
|
image.dx = vxres - ((yy + 1) * vc->vc_font.height);
|
|
|
|
image.dy = xx * vc->vc_font.width;
|
|
|
|
image.width = vc->vc_font.height;
|
|
|
|
image.depth = 1;
|
|
|
|
|
|
|
|
if (attribute) {
|
|
|
|
buf = kmalloc(cellsize, GFP_KERNEL);
|
|
|
|
if (!buf)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (count) {
|
|
|
|
if (count > maxcnt)
|
|
|
|
cnt = maxcnt;
|
|
|
|
else
|
|
|
|
cnt = count;
|
|
|
|
|
|
|
|
image.height = vc->vc_font.width * cnt;
|
|
|
|
pitch = ((image.width + 7) >> 3) + scan_align;
|
|
|
|
pitch &= ~scan_align;
|
|
|
|
size = pitch * image.height + buf_align;
|
|
|
|
size &= ~buf_align;
|
|
|
|
dst = fb_get_buffer_offset(info, &info->pixmap, size);
|
|
|
|
image.data = dst;
|
|
|
|
cw_putcs_aligned(vc, info, s, attribute, cnt, pitch,
|
|
|
|
width, cellsize, &image, buf, dst);
|
|
|
|
image.dy += image.height;
|
|
|
|
count -= cnt;
|
|
|
|
s += cnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* buf is always NULL except when in monochrome mode, so in this case
|
|
|
|
it's a gain to check buf against NULL even though kfree() handles
|
|
|
|
NULL pointers just fine */
|
|
|
|
if (unlikely(buf))
|
|
|
|
kfree(buf);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void cw_clear_margins(struct vc_data *vc, struct fb_info *info,
|
2017-08-19 01:56:40 +08:00
|
|
|
int color, int bottom_only)
|
2005-11-09 13:39:12 +08:00
|
|
|
{
|
|
|
|
unsigned int cw = vc->vc_font.width;
|
|
|
|
unsigned int ch = vc->vc_font.height;
|
|
|
|
unsigned int rw = info->var.yres - (vc->vc_cols*cw);
|
|
|
|
unsigned int bh = info->var.xres - (vc->vc_rows*ch);
|
|
|
|
unsigned int rs = info->var.yres - rw;
|
|
|
|
struct fb_fillrect region;
|
|
|
|
|
2017-08-19 01:56:40 +08:00
|
|
|
region.color = color;
|
2005-11-09 13:39:12 +08:00
|
|
|
region.rop = ROP_COPY;
|
|
|
|
|
fbdev: Detect integer underflow at "struct fbcon_ops"->clear_margins.
syzbot is reporting general protection fault in bitfill_aligned() [1]
caused by integer underflow in bit_clear_margins(). The cause of this
problem is when and how do_vc_resize() updates vc->vc_{cols,rows}.
If vc_do_resize() fails (e.g. kzalloc() fails) when var.xres or var.yres
is going to shrink, vc->vc_{cols,rows} will not be updated. This allows
bit_clear_margins() to see info->var.xres < (vc->vc_cols * cw) or
info->var.yres < (vc->vc_rows * ch). Unexpectedly large rw or bh will
try to overrun the __iomem region and causes general protection fault.
Also, vc_resize(vc, 0, 0) does not set vc->vc_{cols,rows} = 0 due to
new_cols = (cols ? cols : vc->vc_cols);
new_rows = (lines ? lines : vc->vc_rows);
exception. Since cols and lines are calculated as
cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
cols /= vc->vc_font.width;
rows /= vc->vc_font.height;
vc_resize(vc, cols, rows);
in fbcon_modechanged(), var.xres < vc->vc_font.width makes cols = 0
and var.yres < vc->vc_font.height makes rows = 0. This means that
const int fd = open("/dev/fb0", O_ACCMODE);
struct fb_var_screeninfo var = { };
ioctl(fd, FBIOGET_VSCREENINFO, &var);
var.xres = var.yres = 1;
ioctl(fd, FBIOPUT_VSCREENINFO, &var);
easily reproduces integer underflow bug explained above.
Of course, callers of vc_resize() are not handling vc_do_resize() failure
is bad. But we can't avoid vc_resize(vc, 0, 0) which returns 0. Therefore,
as a band-aid workaround, this patch checks integer underflow in
"struct fbcon_ops"->clear_margins call, assuming that
vc->vc_cols * vc->vc_font.width and vc->vc_rows * vc->vc_font.heigh do not
cause integer overflow.
[1] https://syzkaller.appspot.com/bug?id=a565882df74fa76f10d3a6fec4be31098dbb37c6
Reported-and-tested-by: syzbot <syzbot+e5fd3e65515b48c02a30@syzkaller.appspotmail.com>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: stable <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20200715015102.3814-1-penguin-kernel@I-love.SAKURA.ne.jp
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-07-15 09:51:02 +08:00
|
|
|
if ((int) rw > 0 && !bottom_only) {
|
2005-11-09 13:39:12 +08:00
|
|
|
region.dx = 0;
|
|
|
|
region.dy = info->var.yoffset + rs;
|
|
|
|
region.height = rw;
|
|
|
|
region.width = info->var.xres_virtual;
|
|
|
|
info->fbops->fb_fillrect(info, ®ion);
|
|
|
|
}
|
|
|
|
|
fbdev: Detect integer underflow at "struct fbcon_ops"->clear_margins.
syzbot is reporting general protection fault in bitfill_aligned() [1]
caused by integer underflow in bit_clear_margins(). The cause of this
problem is when and how do_vc_resize() updates vc->vc_{cols,rows}.
If vc_do_resize() fails (e.g. kzalloc() fails) when var.xres or var.yres
is going to shrink, vc->vc_{cols,rows} will not be updated. This allows
bit_clear_margins() to see info->var.xres < (vc->vc_cols * cw) or
info->var.yres < (vc->vc_rows * ch). Unexpectedly large rw or bh will
try to overrun the __iomem region and causes general protection fault.
Also, vc_resize(vc, 0, 0) does not set vc->vc_{cols,rows} = 0 due to
new_cols = (cols ? cols : vc->vc_cols);
new_rows = (lines ? lines : vc->vc_rows);
exception. Since cols and lines are calculated as
cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
cols /= vc->vc_font.width;
rows /= vc->vc_font.height;
vc_resize(vc, cols, rows);
in fbcon_modechanged(), var.xres < vc->vc_font.width makes cols = 0
and var.yres < vc->vc_font.height makes rows = 0. This means that
const int fd = open("/dev/fb0", O_ACCMODE);
struct fb_var_screeninfo var = { };
ioctl(fd, FBIOGET_VSCREENINFO, &var);
var.xres = var.yres = 1;
ioctl(fd, FBIOPUT_VSCREENINFO, &var);
easily reproduces integer underflow bug explained above.
Of course, callers of vc_resize() are not handling vc_do_resize() failure
is bad. But we can't avoid vc_resize(vc, 0, 0) which returns 0. Therefore,
as a band-aid workaround, this patch checks integer underflow in
"struct fbcon_ops"->clear_margins call, assuming that
vc->vc_cols * vc->vc_font.width and vc->vc_rows * vc->vc_font.heigh do not
cause integer overflow.
[1] https://syzkaller.appspot.com/bug?id=a565882df74fa76f10d3a6fec4be31098dbb37c6
Reported-and-tested-by: syzbot <syzbot+e5fd3e65515b48c02a30@syzkaller.appspotmail.com>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: stable <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20200715015102.3814-1-penguin-kernel@I-love.SAKURA.ne.jp
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-07-15 09:51:02 +08:00
|
|
|
if ((int) bh > 0) {
|
2005-11-09 13:39:12 +08:00
|
|
|
region.dx = info->var.xoffset;
|
|
|
|
region.dy = info->var.yoffset;
|
|
|
|
region.height = info->var.yres;
|
|
|
|
region.width = bh;
|
|
|
|
info->fbops->fb_fillrect(info, ®ion);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-01-10 12:52:56 +08:00
|
|
|
static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
|
2020-09-09 01:56:27 +08:00
|
|
|
int fg, int bg)
|
2005-11-09 13:39:12 +08:00
|
|
|
{
|
|
|
|
struct fb_cursor cursor;
|
2006-01-10 12:52:56 +08:00
|
|
|
struct fbcon_ops *ops = info->fbcon_par;
|
2005-11-09 13:39:12 +08:00
|
|
|
unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
|
|
|
|
int w = (vc->vc_font.height + 7) >> 3, c;
|
2020-06-15 15:48:33 +08:00
|
|
|
int y = real_y(ops->p, vc->state.y);
|
2020-06-15 15:48:58 +08:00
|
|
|
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
|
2005-11-09 13:39:12 +08:00
|
|
|
int err = 1, dx, dy;
|
|
|
|
char *src;
|
2022-02-02 21:55:31 +08:00
|
|
|
u32 vxres = GETVXRES(ops->p, info);
|
2005-11-09 13:39:12 +08:00
|
|
|
|
|
|
|
if (!ops->fontbuffer)
|
|
|
|
return;
|
|
|
|
|
|
|
|
cursor.set = 0;
|
|
|
|
|
|
|
|
c = scr_readw((u16 *) vc->vc_pos);
|
|
|
|
attribute = get_attribute(info, c);
|
|
|
|
src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
|
|
|
|
|
|
|
|
if (ops->cursor_state.image.data != src ||
|
|
|
|
ops->cursor_reset) {
|
|
|
|
ops->cursor_state.image.data = src;
|
|
|
|
cursor.set |= FB_CUR_SETIMAGE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attribute) {
|
|
|
|
u8 *dst;
|
|
|
|
|
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 04:55:00 +08:00
|
|
|
dst = kmalloc_array(w, vc->vc_font.width, GFP_ATOMIC);
|
2005-11-09 13:39:12 +08:00
|
|
|
if (!dst)
|
|
|
|
return;
|
|
|
|
kfree(ops->cursor_data);
|
|
|
|
ops->cursor_data = dst;
|
|
|
|
cw_update_attr(dst, src, attribute, vc);
|
|
|
|
src = dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ops->cursor_state.image.fg_color != fg ||
|
|
|
|
ops->cursor_state.image.bg_color != bg ||
|
|
|
|
ops->cursor_reset) {
|
|
|
|
ops->cursor_state.image.fg_color = fg;
|
|
|
|
ops->cursor_state.image.bg_color = bg;
|
|
|
|
cursor.set |= FB_CUR_SETCMAP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ops->cursor_state.image.height != vc->vc_font.width ||
|
|
|
|
ops->cursor_state.image.width != vc->vc_font.height ||
|
|
|
|
ops->cursor_reset) {
|
|
|
|
ops->cursor_state.image.height = vc->vc_font.width;
|
|
|
|
ops->cursor_state.image.width = vc->vc_font.height;
|
|
|
|
cursor.set |= FB_CUR_SETSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
dx = vxres - ((y * vc->vc_font.height) + vc->vc_font.height);
|
2020-06-15 15:48:33 +08:00
|
|
|
dy = vc->state.x * vc->vc_font.width;
|
2005-11-09 13:39:12 +08:00
|
|
|
|
|
|
|
if (ops->cursor_state.image.dx != dx ||
|
|
|
|
ops->cursor_state.image.dy != dy ||
|
|
|
|
ops->cursor_reset) {
|
|
|
|
ops->cursor_state.image.dx = dx;
|
|
|
|
ops->cursor_state.image.dy = dy;
|
|
|
|
cursor.set |= FB_CUR_SETPOS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
|
|
|
|
ops->cursor_reset) {
|
|
|
|
ops->cursor_state.hot.x = cursor.hot.y = 0;
|
|
|
|
cursor.set |= FB_CUR_SETHOT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cursor.set & FB_CUR_SETSIZE ||
|
2006-01-10 12:52:56 +08:00
|
|
|
vc->vc_cursor_type != ops->p->cursor_shape ||
|
2005-11-09 13:39:12 +08:00
|
|
|
ops->cursor_state.mask == NULL ||
|
|
|
|
ops->cursor_reset) {
|
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 04:55:00 +08:00
|
|
|
char *tmp, *mask = kmalloc_array(w, vc->vc_font.width,
|
|
|
|
GFP_ATOMIC);
|
2005-11-09 13:39:12 +08:00
|
|
|
int cur_height, size, i = 0;
|
|
|
|
int width = (vc->vc_font.width + 7)/8;
|
|
|
|
|
|
|
|
if (!mask)
|
|
|
|
return;
|
|
|
|
|
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 04:55:00 +08:00
|
|
|
tmp = kmalloc_array(width, vc->vc_font.height, GFP_ATOMIC);
|
2005-11-09 13:39:12 +08:00
|
|
|
|
|
|
|
if (!tmp) {
|
|
|
|
kfree(mask);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
kfree(ops->cursor_state.mask);
|
|
|
|
ops->cursor_state.mask = mask;
|
|
|
|
|
2006-01-10 12:52:56 +08:00
|
|
|
ops->p->cursor_shape = vc->vc_cursor_type;
|
2005-11-09 13:39:12 +08:00
|
|
|
cursor.set |= FB_CUR_SETSHAPE;
|
|
|
|
|
2020-06-15 15:48:57 +08:00
|
|
|
switch (CUR_SIZE(ops->p->cursor_shape)) {
|
2005-11-09 13:39:12 +08:00
|
|
|
case CUR_NONE:
|
|
|
|
cur_height = 0;
|
|
|
|
break;
|
|
|
|
case CUR_UNDERLINE:
|
|
|
|
cur_height = (vc->vc_font.height < 10) ? 1 : 2;
|
|
|
|
break;
|
|
|
|
case CUR_LOWER_THIRD:
|
|
|
|
cur_height = vc->vc_font.height/3;
|
|
|
|
break;
|
|
|
|
case CUR_LOWER_HALF:
|
|
|
|
cur_height = vc->vc_font.height >> 1;
|
|
|
|
break;
|
|
|
|
case CUR_TWO_THIRDS:
|
|
|
|
cur_height = (vc->vc_font.height << 1)/3;
|
|
|
|
break;
|
|
|
|
case CUR_BLOCK:
|
|
|
|
default:
|
|
|
|
cur_height = vc->vc_font.height;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
size = (vc->vc_font.height - cur_height) * width;
|
|
|
|
while (size--)
|
|
|
|
tmp[i++] = 0;
|
|
|
|
size = cur_height * width;
|
|
|
|
while (size--)
|
|
|
|
tmp[i++] = 0xff;
|
|
|
|
memset(mask, 0, w * vc->vc_font.width);
|
|
|
|
rotate_cw(tmp, mask, vc->vc_font.width, vc->vc_font.height);
|
|
|
|
kfree(tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (mode) {
|
|
|
|
case CM_ERASE:
|
|
|
|
ops->cursor_state.enable = 0;
|
|
|
|
break;
|
|
|
|
case CM_DRAW:
|
|
|
|
case CM_MOVE:
|
|
|
|
default:
|
|
|
|
ops->cursor_state.enable = (use_sw) ? 0 : 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
cursor.image.data = src;
|
|
|
|
cursor.image.fg_color = ops->cursor_state.image.fg_color;
|
|
|
|
cursor.image.bg_color = ops->cursor_state.image.bg_color;
|
|
|
|
cursor.image.dx = ops->cursor_state.image.dx;
|
|
|
|
cursor.image.dy = ops->cursor_state.image.dy;
|
|
|
|
cursor.image.height = ops->cursor_state.image.height;
|
|
|
|
cursor.image.width = ops->cursor_state.image.width;
|
|
|
|
cursor.hot.x = ops->cursor_state.hot.x;
|
|
|
|
cursor.hot.y = ops->cursor_state.hot.y;
|
|
|
|
cursor.mask = ops->cursor_state.mask;
|
|
|
|
cursor.enable = ops->cursor_state.enable;
|
|
|
|
cursor.image.depth = 1;
|
|
|
|
cursor.rop = ROP_XOR;
|
|
|
|
|
|
|
|
if (info->fbops->fb_cursor)
|
|
|
|
err = info->fbops->fb_cursor(info, &cursor);
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
soft_cursor(info, &cursor);
|
|
|
|
|
|
|
|
ops->cursor_reset = 0;
|
|
|
|
}
|
|
|
|
|
2006-10-03 16:15:05 +08:00
|
|
|
static int cw_update_start(struct fb_info *info)
|
2005-11-09 13:39:12 +08:00
|
|
|
{
|
|
|
|
struct fbcon_ops *ops = info->fbcon_par;
|
2022-02-02 21:55:31 +08:00
|
|
|
u32 vxres = GETVXRES(ops->p, info);
|
2005-11-09 13:39:12 +08:00
|
|
|
u32 xoffset;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
xoffset = vxres - (info->var.xres + ops->var.yoffset);
|
|
|
|
ops->var.yoffset = ops->var.xoffset;
|
|
|
|
ops->var.xoffset = xoffset;
|
|
|
|
err = fb_pan_display(info, &ops->var);
|
|
|
|
ops->var.xoffset = info->var.xoffset;
|
|
|
|
ops->var.yoffset = info->var.yoffset;
|
|
|
|
ops->var.vmode = info->var.vmode;
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
void fbcon_rotate_cw(struct fbcon_ops *ops)
|
|
|
|
{
|
Revert "fbdev: Garbage collect fbdev scrolling acceleration, part 1 (from TODO list)"
This reverts commit b3ec8cdf457e5e63d396fe1346cc788cf7c1b578.
Revert the second (of 2) commits which disabled scrolling acceleration
in fbcon/fbdev. It introduced a regression for fbdev-supported graphic
cards because of the performance penalty by doing screen scrolling by
software instead of using the existing graphic card 2D hardware
acceleration.
Console scrolling acceleration was disabled by dropping code which
checked at runtime the driver hardware capabilities for the
BINFO_HWACCEL_COPYAREA or FBINFO_HWACCEL_FILLRECT flags and if set, it
enabled scrollmode SCROLL_MOVE which uses hardware acceleration to move
screen contents. After dropping those checks scrollmode was hard-wired
to SCROLL_REDRAW instead, which forces all graphic cards to redraw every
character at the new screen position when scrolling.
This change effectively disabled all hardware-based scrolling acceleration for
ALL drivers, because now all kind of 2D hardware acceleration (bitblt,
fillrect) in the drivers isn't used any longer.
The original commit message mentions that only 3 DRM drivers (nouveau, omapdrm
and gma500) used hardware acceleration in the past and thus code for checking
and using scrolling acceleration is obsolete.
This statement is NOT TRUE, because beside the DRM drivers there are around 35
other fbdev drivers which depend on fbdev/fbcon and still provide hardware
acceleration for fbdev/fbcon.
The original commit message also states that syzbot found lots of bugs in fbcon
and thus it's "often the solution to just delete code and remove features".
This is true, and the bugs - which actually affected all users of fbcon,
including DRM - were fixed, or code was dropped like e.g. the support for
software scrollback in vgacon (commit 973c096f6a85).
So to further analyze which bugs were found by syzbot, I've looked through all
patches in drivers/video which were tagged with syzbot or syzkaller back to
year 2005. The vast majority fixed the reported issues on a higher level, e.g.
when screen is to be resized, or when font size is to be changed. The few ones
which touched driver code fixed a real driver bug, e.g. by adding a check.
But NONE of those patches touched code of either the SCROLL_MOVE or the
SCROLL_REDRAW case.
That means, there was no real reason why SCROLL_MOVE had to be ripped-out and
just SCROLL_REDRAW had to be used instead. The only reason I can imagine so far
was that SCROLL_MOVE wasn't used by DRM and as such it was assumed that it
could go away. That argument completely missed the fact that SCROLL_MOVE is
still heavily used by fbdev (non-DRM) drivers.
Some people mention that using memcpy() instead of the hardware acceleration is
pretty much the same speed. But that's not true, at least not for older graphic
cards and machines where we see speed decreases by factor 10 and more and thus
this change leads to console responsiveness way worse than before.
That's why the original commit is to be reverted. By reverting we
reintroduce hardware-based scrolling acceleration and fix the
performance regression for fbdev drivers.
There isn't any impact on DRM when reverting those patches.
Signed-off-by: Helge Deller <deller@gmx.de>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Sven Schnelle <svens@stackframe.org>
Cc: stable@vger.kernel.org # v5.16+
Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: https://patchwork.freedesktop.org/patch/msgid/20220202135531.92183-2-deller@gmx.de
2022-02-02 21:55:29 +08:00
|
|
|
ops->bmove = cw_bmove;
|
2005-11-09 13:39:12 +08:00
|
|
|
ops->clear = cw_clear;
|
|
|
|
ops->putcs = cw_putcs;
|
|
|
|
ops->clear_margins = cw_clear_margins;
|
|
|
|
ops->cursor = cw_cursor;
|
|
|
|
ops->update_start = cw_update_start;
|
|
|
|
}
|