Commit eacf91b0 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull fbdev updates from Helge Deller:
 "One potential buffer overflow fix in the framebuffer registration
  function, some fixes for the imxfb, nvidiafb and simplefb drivers, and
  a bunch of cleanups for fbcon, kyrofb and svgalib.

  Framework fixes:
   - fix potential buffer overflow in do_register_framebuffer() [Yongzhen Zhang]

  Driver fixes:
   - imxfb: prevent null-ptr-deref [Chenyuan Yang]
   - nvidiafb: fix build on 32-bit ARCH=um [Johannes Berg]
   - nvidiafb: add depends on HAS_IOPORT [Randy Dunlap]
   - simplefb: Use of_reserved_mem_region_to_resource() for "memory-region" [Rob Herring]

  Cleanups:
   - fbcon: various code cleanups wrt blinking [Ville Syrjälä]
   - kyrofb: Convert to devm_*() functions [Giovanni Di Santi]
   - svgalib: Coding style cleanups [Darshan R.]
   - Fix typo in Kconfig text for FB_DEVICE [Daniel Palmer]"

* tag 'fbdev-for-6.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/linux-fbdev:
  fbcon: Use 'bool' where appopriate
  fbcon: Introduce get_{fg,bg}_color()
  fbcon: fbcon_is_inactive() -> fbcon_is_active()
  fbcon: fbcon_cursor_noblink -> fbcon_cursor_blink
  fbdev: Fix typo in Kconfig text for FB_DEVICE
  fbdev: imxfb: Check fb_add_videomode to prevent null-ptr-deref
  fbdev: svgalib: Clean up coding style
  fbdev: kyro: Use devm_ioremap_wc() for screen mem
  fbdev: kyro: Use devm_ioremap() for mmio registers
  fbdev: kyro: Add missing PCI memory region request
  fbdev: simplefb: Use of_reserved_mem_region_to_resource() for "memory-region"
  fbdev: fix potential buffer overflow in do_register_framebuffer()
  fbdev: nvidiafb: add depends on HAS_IOPORT
  fbdev: nvidiafb: fix build on 32-bit ARCH=um
parents 70618359 81b96e4a
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -660,7 +660,7 @@ config FB_ATMEL

config FB_NVIDIA
	tristate "nVidia Framebuffer Support"
	depends on FB && PCI
	depends on FB && PCI && HAS_IOPORT
	select FB_CFB_FILLRECT
	select FB_CFB_COPYAREA
	select FB_CFB_IMAGEBLIT
+1 −1
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@ config FB_DEVICE
	default FB
	help
	  Say Y here if you want the legacy /dev/fb* device file and
	  interfaces within sysfs anc procfs. It is only required if you
	  interfaces within sysfs and procfs. It is only required if you
	  have userspace programs that depend on fbdev for graphics output.
	  This does not affect the framebuffer console. If unsure, say N.

+45 −32
Original line number Diff line number Diff line
@@ -135,9 +135,9 @@ static int logo_shown = FBCON_LOGO_CANSHOW;
/* console mappings */
static unsigned int first_fb_vc;
static unsigned int last_fb_vc = MAX_NR_CONSOLES - 1;
static int fbcon_is_default = 1;
static bool fbcon_is_default = true;
static int primary_device = -1;
static int fbcon_has_console_bind;
static bool fbcon_has_console_bind;

#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
static int map_override;
@@ -172,7 +172,7 @@ static const struct consw fb_con;

#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)

static int fbcon_cursor_noblink;
static bool fbcon_cursor_blink = true;

#define divides(a, b)	((!(a) || (b)%(a)) ? 0 : 1)

@@ -289,16 +289,16 @@ static bool fbcon_skip_panic(struct fb_info *info)
#endif
}

static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
static inline bool fbcon_is_active(struct vc_data *vc, struct fb_info *info)
{
	struct fbcon_ops *ops = info->fbcon_par;

	return (info->state != FBINFO_STATE_RUNNING ||
		vc->vc_mode != KD_TEXT || ops->graphics || fbcon_skip_panic(info));
	return info->state == FBINFO_STATE_RUNNING &&
		vc->vc_mode == KD_TEXT && !ops->graphics && !fbcon_skip_panic(info);
}

static int get_color(struct vc_data *vc, struct fb_info *info,
	      u16 c, int is_fg)
		     u16 c, bool is_fg)
{
	int depth = fb_get_color_depth(&info->var, &info->fix);
	int color = 0;
@@ -364,6 +364,16 @@ static int get_color(struct vc_data *vc, struct fb_info *info,
	return color;
}

static int get_fg_color(struct vc_data *vc, struct fb_info *info, u16 c)
{
	return get_color(vc, info, c, true);
}

static int get_bg_color(struct vc_data *vc, struct fb_info *info, u16 c)
{
	return get_color(vc, info, c, false);
}

static void fb_flashcursor(struct work_struct *work)
{
	struct fbcon_ops *ops = container_of(work, struct fbcon_ops, cursor_work.work);
@@ -395,8 +405,9 @@ static void fb_flashcursor(struct work_struct *work)

	c = scr_readw((u16 *) vc->vc_pos);
	enable = ops->cursor_flash && !ops->cursor_state.enable;
	ops->cursor(vc, info, enable, get_color(vc, info, c, 1),
		    get_color(vc, info, c, 0));
	ops->cursor(vc, info, enable,
		    get_fg_color(vc, info, c),
		    get_bg_color(vc, info, c));
	console_unlock();

	queue_delayed_work(system_power_efficient_wq, &ops->cursor_work,
@@ -407,7 +418,7 @@ static void fbcon_add_cursor_work(struct fb_info *info)
{
	struct fbcon_ops *ops = info->fbcon_par;

	if (!fbcon_cursor_noblink)
	if (fbcon_cursor_blink)
		queue_delayed_work(system_power_efficient_wq, &ops->cursor_work,
				   ops->cur_blink_jiffies);
}
@@ -464,7 +475,7 @@ static int __init fb_console_setup(char *this_opt)
				last_fb_vc = simple_strtoul(options, &options, 10) - 1;
			if (last_fb_vc < first_fb_vc || last_fb_vc >= MAX_NR_CONSOLES)
				last_fb_vc = MAX_NR_CONSOLES - 1;
			fbcon_is_default = 0;
			fbcon_is_default = false;
			continue;
		}

@@ -559,7 +570,7 @@ static int do_fbcon_takeover(int show_logo)
			con2fb_map[i] = -1;
		info_idx = -1;
	} else {
		fbcon_has_console_bind = 1;
		fbcon_has_console_bind = true;
	}

	return err;
@@ -1267,7 +1278,7 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
	struct fbcon_display *p = &fb_display[vc->vc_num];
	u_int y_break;

	if (fbcon_is_inactive(vc, info))
	if (!fbcon_is_active(vc, info))
		return;

	if (!height || !width)
@@ -1311,10 +1322,10 @@ static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
	struct fbcon_display *p = &fb_display[vc->vc_num];
	struct fbcon_ops *ops = info->fbcon_par;

	if (!fbcon_is_inactive(vc, info))
	if (fbcon_is_active(vc, info))
		ops->putcs(vc, info, s, count, real_y(p, ypos), xpos,
			   get_color(vc, info, scr_readw(s), 1),
			   get_color(vc, info, scr_readw(s), 0));
			   get_fg_color(vc, info, scr_readw(s)),
			   get_bg_color(vc, info, scr_readw(s)));
}

static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
@@ -1322,7 +1333,7 @@ static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
	struct fbcon_ops *ops = info->fbcon_par;

	if (!fbcon_is_inactive(vc, info))
	if (fbcon_is_active(vc, info))
		ops->clear_margins(vc, info, margin_color, bottom_only);
}

@@ -1334,7 +1345,7 @@ static void fbcon_cursor(struct vc_data *vc, bool enable)

	ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);

	if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
	if (!fbcon_is_active(vc, info) || vc->vc_deccm != 1)
		return;

	if (vc->vc_cursor_type & CUR_SW)
@@ -1347,8 +1358,9 @@ static void fbcon_cursor(struct vc_data *vc, bool enable)
	if (!ops->cursor)
		return;

	ops->cursor(vc, info, enable, get_color(vc, info, c, 1),
		    get_color(vc, info, c, 0));
	ops->cursor(vc, info, enable,
		    get_fg_color(vc, info, c),
		    get_bg_color(vc, info, c));
}

static int scrollback_phys_max = 0;
@@ -1740,7 +1752,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
	struct fbcon_display *p = &fb_display[vc->vc_num];

	if (fbcon_is_inactive(vc, info))
	if (!fbcon_is_active(vc, info))
		return;

	if (!width || !height)
@@ -1764,7 +1776,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
	struct fbcon_display *p = &fb_display[vc->vc_num];
	int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;

	if (fbcon_is_inactive(vc, info))
	if (!fbcon_is_active(vc, info))
		return true;

	fbcon_cursor(vc, false);
@@ -2148,7 +2160,7 @@ static bool fbcon_switch(struct vc_data *vc)
			fbcon_del_cursor_work(old_info);
	}

	if (fbcon_is_inactive(vc, info) ||
	if (!fbcon_is_active(vc, info) ||
	    ops->blank_state != FB_BLANK_UNBLANK)
		fbcon_del_cursor_work(info);
	else
@@ -2188,7 +2200,7 @@ static bool fbcon_switch(struct vc_data *vc)
	scrollback_max = 0;
	scrollback_current = 0;

	if (!fbcon_is_inactive(vc, info)) {
	if (fbcon_is_active(vc, info)) {
	    ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
	    ops->update_start(info);
	}
@@ -2244,7 +2256,7 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
		}
	}

 	if (!fbcon_is_inactive(vc, info)) {
	if (fbcon_is_active(vc, info)) {
		if (ops->blank_state != blank) {
			ops->blank_state = blank;
			fbcon_cursor(vc, !blank);
@@ -2258,7 +2270,7 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
			update_screen(vc);
	}

	if (mode_switch || fbcon_is_inactive(vc, info) ||
	if (mode_switch || !fbcon_is_active(vc, info) ||
	    ops->blank_state != FB_BLANK_UNBLANK)
		fbcon_del_cursor_work(info);
	else
@@ -2588,7 +2600,7 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table)
	int i, j, k, depth;
	u8 val;

	if (fbcon_is_inactive(vc, info))
	if (!fbcon_is_active(vc, info))
		return;

	if (!con_is_visible(vc))
@@ -2688,7 +2700,7 @@ static void fbcon_modechanged(struct fb_info *info)
		scrollback_max = 0;
		scrollback_current = 0;

		if (!fbcon_is_inactive(vc, info)) {
		if (fbcon_is_active(vc, info)) {
		    ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
		    ops->update_start(info);
		}
@@ -2806,7 +2818,7 @@ static void fbcon_unbind(void)
				fbcon_is_default);

	if (!ret)
		fbcon_has_console_bind = 0;
		fbcon_has_console_bind = false;
}
#else
static inline void fbcon_unbind(void) {}
@@ -3257,8 +3269,9 @@ static ssize_t cursor_blink_store(struct device *device,
				  const char *buf, size_t count)
{
	struct fb_info *info;
	int blink, idx;
	char **last = NULL;
	bool blink;
	int idx;

	console_lock();
	idx = con2fb_map[fg_console];
@@ -3274,10 +3287,10 @@ static ssize_t cursor_blink_store(struct device *device,
	blink = simple_strtoul(buf, last, 0);

	if (blink) {
		fbcon_cursor_noblink = 0;
		fbcon_cursor_blink = true;
		fbcon_add_cursor_work(info);
	} else {
		fbcon_cursor_noblink = 1;
		fbcon_cursor_blink = false;
		fbcon_del_cursor_work(info);
	}

+3 −0
Original line number Diff line number Diff line
@@ -449,6 +449,9 @@ static int do_register_framebuffer(struct fb_info *fb_info)
		if (!registered_fb[i])
			break;

	if (i >= FB_MAX)
		return -ENXIO;

	if (!fb_info->modelist.prev || !fb_info->modelist.next)
		INIT_LIST_HEAD(&fb_info->modelist);

+42 −53
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@
#include <asm/types.h>
#include <asm/io.h>


/* Write a CRT register value spread across multiple registers */
void svga_wcrt_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value)
{
@@ -32,7 +31,8 @@ void svga_wcrt_multi(void __iomem *regbase, const struct vga_regset *regset, u32
		while (bitnum <= regset->highbit) {
			bitval = 1 << bitnum;
			regval = regval & ~bitval;
			if (value & 1) regval = regval | bitval;
			if (value & 1)
				regval = regval | bitval;
			bitnum++;
			value = value >> 1;
		}
@@ -52,7 +52,8 @@ void svga_wseq_multi(void __iomem *regbase, const struct vga_regset *regset, u32
		while (bitnum <= regset->highbit) {
			bitval = 1 << bitnum;
			regval = regval & ~bitval;
			if (value & 1) regval = regval | bitval;
			if (value & 1)
				regval = regval | bitval;
			bitnum++;
			value = value >> 1;
		}
@@ -72,10 +73,8 @@ static unsigned int svga_regset_size(const struct vga_regset *regset)
	return 1 << count;
}


/* ------------------------------------------------------------------------- */


/* Set graphics controller registers to sane values */
void svga_set_default_gfx_regs(void __iomem *regbase)
{
@@ -188,10 +187,8 @@ void svga_dump_var(struct fb_var_screeninfo *var, int node)
}
#endif  /*  0  */


/* ------------------------------------------------------------------------- */


void svga_settile(struct fb_info *info, struct fb_tilemap *map)
{
	const u8 *font = map->data;
@@ -293,11 +290,11 @@ void svga_tileblit(struct fb_info *info, struct fb_tileblit *blit)
			fb_writeb(attr, fb2 + 1);
			fb2 += colstride;
			i++;
			if (i == blit->length) return;
			if (i == blit->length)
				return;
		}
		fb += rowstride;
	}

}

/* Set cursor in text (tileblit) mode */
@@ -375,7 +372,6 @@ EXPORT_SYMBOL(svga_get_caps);

/* ------------------------------------------------------------------------- */


/*
 *  Compute PLL settings (M, N, R)
 *  F_VCO = (F_BASE * M) / N
@@ -425,12 +421,11 @@ int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u
			*n = an;
		}

		if (f_current <= f_vco) {
		if (f_current <= f_vco)
			am++;
		} else {
		else
			an++;
	}
	}

	f_current = (pll->f_base * *m) / *n;
	pr_debug("fb%d: found frequency: %d kHz (VCO %d kHz)\n", node, (int)(f_current >> ar), (int)f_current);
@@ -438,10 +433,8 @@ int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u
	return 0;
}


/* ------------------------------------------------------------------------- */


/* Check CRT timing values */
int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var, int node)
{
@@ -597,18 +590,15 @@ void svga_set_timings(void __iomem *regbase, const struct svga_timing_regs *tm,
	vga_w(regbase, VGA_MIS_W, regval);
}


/* ------------------------------------------------------------------------- */


static inline int match_format(const struct svga_fb_format *frm,
			       struct fb_var_screeninfo *var)
{
	int i = 0;
	int stored = -EINVAL;

	while (frm->bits_per_pixel != SVGA_FORMAT_END_VAL)
	{
	while (frm->bits_per_pixel != SVGA_FORMAT_END_VAL) {
		if ((var->bits_per_pixel == frm->bits_per_pixel) &&
		    (var->red.length     <= frm->red.length)     &&
		    (var->green.length   <= frm->green.length)   &&
@@ -648,7 +638,6 @@ int svga_match_format(const struct svga_fb_format *frm,
	return i;
}


EXPORT_SYMBOL(svga_wcrt_multi);
EXPORT_SYMBOL(svga_wseq_multi);

Loading