[patchv2,3/3] VT: Bump font size limitation to 64x128 pixels

Message ID 20221218003237.503424466@ens-lyon.org
State New
Headers
Series VT: Support >32x32 fonts for hidpi displays |

Commit Message

Samuel Thibault Dec. 18, 2022, 12:32 a.m. UTC
  This moves 32x32 font size limitation checking down to drivers, so that
fbcon can allow large fonts.

We still keep a limitation to 64x128 pixels so as to have a simple bounded
allocation for con_font_get and in the userland kbd tool. That glyph size
will however be enough to have 128x36 characters on a "16/9 8K display".

Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>

---
V1 -> V2: Switch con_font_get to kvmalloc/kvfree instead of kmalloc/kfree
  

Comments

Alexey Gladkov Dec. 18, 2022, 2:39 p.m. UTC | #1
On Sun, Dec 18, 2022 at 01:32:12AM +0100, Samuel Thibault wrote:
> This moves 32x32 font size limitation checking down to drivers, so that
> fbcon can allow large fonts.
> 
> We still keep a limitation to 64x128 pixels so as to have a simple bounded
> allocation for con_font_get and in the userland kbd tool. That glyph size
> will however be enough to have 128x36 characters on a "16/9 8K display".
> 
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> 
> ---
> V1 -> V2: Switch con_font_get to kvmalloc/kvfree instead of kmalloc/kfree
> 
> Index: linux-6.0/drivers/tty/vt/vt.c
> ===================================================================
> --- linux-6.0.orig/drivers/tty/vt/vt.c
> +++ linux-6.0/drivers/tty/vt/vt.c
> @@ -4575,17 +4575,20 @@ void reset_palette(struct vc_data *vc)
>  /*
>   *  Font switching
>   *
> - *  Currently we only support fonts up to 32 pixels wide, at a maximum height
> - *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, 
> - *  depending on width) reserved for each character which is kinda wasty, but 
> - *  this is done in order to maintain compatibility with the EGA/VGA fonts. It 
> - *  is up to the actual low-level console-driver convert data into its favorite
> - *  format (maybe we should add a `fontoffset' field to the `display'
> - *  structure so we won't have to convert the fontdata all the time.
> + *  Currently we only support fonts up to 128 pixels wide, at a maximum height
> + *  of 128 pixels. Userspace fontdata may have to be stored with 32 bytes
> + *  (shorts/ints, depending on width) reserved for each character which is
> + *  kinda wasty, but this is done in order to maintain compatibility with the
> + *  EGA/VGA fonts. It is up to the actual low-level console-driver convert data
> + *  into its favorite format (maybe we should add a `fontoffset' field to the
> + *  `display' structure so we won't have to convert the fontdata all the time.
>   *  /Jes
>   */
>  
> -#define max_font_size 65536
> +#define max_font_width	64
> +#define max_font_height	128
> +#define max_font_glyphs	512
> +#define max_font_size	(max_font_glyphs*max_font_width*max_font_height)

As a suggestion that you can safely ignore. Maybe make max_font_glyphs a
sysctl parameter to be able to use larger fonts ?

I get requests from time to time in kbd that it is not possible to load a
larger font.

>  static int con_font_get(struct vc_data *vc, struct console_font_op *op)
>  {
> @@ -4595,7 +4598,7 @@ static int con_font_get(struct vc_data *
>  	unsigned int vpitch = op->op == KD_FONT_OP_GET_TALL ? op->height : 32;
>  
>  	if (op->data) {
> -		font.data = kmalloc(max_font_size, GFP_KERNEL);
> +		font.data = kvmalloc(max_font_size, GFP_KERNEL);
>  		if (!font.data)
>  			return -ENOMEM;
>  	} else
> @@ -4630,7 +4633,7 @@ static int con_font_get(struct vc_data *
>  		rc = -EFAULT;
>  
>  out:
> -	kfree(font.data);
> +	kvfree(font.data);
>  	return rc;
>  }
>  
> @@ -4645,9 +4648,10 @@ static int con_font_set(struct vc_data *
>  		return -EINVAL;
>  	if (!op->data)
>  		return -EINVAL;
> -	if (op->charcount > 512)
> +	if (op->charcount > max_font_glyphs)
>  		return -EINVAL;
> -	if (op->width <= 0 || op->width > 32 || !op->height || op->height > 32)
> +	if (op->width <= 0 || op->width > max_font_width || !op->height ||
> +	    op->height > max_font_height)
>  		return -EINVAL;
>  	if (vpitch < op->height)
>  		return -EINVAL;
> Index: linux-6.0/drivers/usb/misc/sisusbvga/sisusb_con.c
> ===================================================================
> --- linux-6.0.orig/drivers/usb/misc/sisusbvga/sisusb_con.c
> +++ linux-6.0/drivers/usb/misc/sisusbvga/sisusb_con.c
> @@ -1203,7 +1203,7 @@ sisusbcon_font_set(struct vc_data *c, st
>  	struct sisusb_usb_data *sisusb;
>  	unsigned charcount = font->charcount;
>  
> -	if (font->width != 8 || vpitch != 32 ||
> +	if (font->width != 8 || font->height > 32 || vpitch != 32 ||
>  	    (charcount != 256 && charcount != 512))
>  		return -EINVAL;
>  
> Index: linux-6.0/drivers/video/console/vgacon.c
> ===================================================================
> --- linux-6.0.orig/drivers/video/console/vgacon.c
> +++ linux-6.0/drivers/video/console/vgacon.c
> @@ -1037,7 +1037,7 @@ static int vgacon_font_set(struct vc_dat
>  	if (vga_video_type < VIDEO_TYPE_EGAM)
>  		return -EINVAL;
>  
> -	if (font->width != VGA_FONTWIDTH || vpitch != 32 ||
> +	if (font->width != VGA_FONTWIDTH || font->height > 32 || vpitch != 32 ||
>  	    (charcount != 256 && charcount != 512))
>  		return -EINVAL;
>  
> Index: linux-6.0/drivers/video/fbdev/core/fbcon.c
> ===================================================================
> --- linux-6.0.orig/drivers/video/fbdev/core/fbcon.c
> +++ linux-6.0/drivers/video/fbdev/core/fbcon.c
> @@ -2279,6 +2279,8 @@ static int fbcon_get_font(struct vc_data
>  
>  	font->width = vc->vc_font.width;
>  	font->height = vc->vc_font.height;
> +	if (font->height > vpitch)
> +		return -ENOSPC;
>  	font->charcount = vc->vc_hi_font_mask ? 512 : 256;
>  	if (!font->data)
>  		return 0;
> 
> _______________________________________________
> kbd mailing list
> kbd@lists.altlinux.org
> https://lists.altlinux.org/mailman/listinfo/kbd
>
  
Samuel Thibault Dec. 18, 2022, 2:55 p.m. UTC | #2
Hello,

Alexey Gladkov, le dim. 18 déc. 2022 15:39:38 +0100, a ecrit:
> On Sun, Dec 18, 2022 at 01:32:12AM +0100, Samuel Thibault wrote:
> > This moves 32x32 font size limitation checking down to drivers, so that
> > fbcon can allow large fonts.
> > 
> > We still keep a limitation to 64x128 pixels so as to have a simple bounded
> > allocation for con_font_get and in the userland kbd tool. That glyph size
> > will however be enough to have 128x36 characters on a "16/9 8K display".
> > 
> > Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> > 
> > ---
> > V1 -> V2: Switch con_font_get to kvmalloc/kvfree instead of kmalloc/kfree
> > 
> > Index: linux-6.0/drivers/tty/vt/vt.c
> > ===================================================================
> > --- linux-6.0.orig/drivers/tty/vt/vt.c
> > +++ linux-6.0/drivers/tty/vt/vt.c
> > @@ -4575,17 +4575,20 @@ void reset_palette(struct vc_data *vc)
> >  /*
> >   *  Font switching
> >   *
> > - *  Currently we only support fonts up to 32 pixels wide, at a maximum height
> > - *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, 
> > - *  depending on width) reserved for each character which is kinda wasty, but 
> > - *  this is done in order to maintain compatibility with the EGA/VGA fonts. It 
> > - *  is up to the actual low-level console-driver convert data into its favorite
> > - *  format (maybe we should add a `fontoffset' field to the `display'
> > - *  structure so we won't have to convert the fontdata all the time.
> > + *  Currently we only support fonts up to 128 pixels wide, at a maximum height
> > + *  of 128 pixels. Userspace fontdata may have to be stored with 32 bytes
> > + *  (shorts/ints, depending on width) reserved for each character which is
> > + *  kinda wasty, but this is done in order to maintain compatibility with the
> > + *  EGA/VGA fonts. It is up to the actual low-level console-driver convert data
> > + *  into its favorite format (maybe we should add a `fontoffset' field to the
> > + *  `display' structure so we won't have to convert the fontdata all the time.
> >   *  /Jes
> >   */
> >  
> > -#define max_font_size 65536
> > +#define max_font_width	64
> > +#define max_font_height	128
> > +#define max_font_glyphs	512
> > +#define max_font_size	(max_font_glyphs*max_font_width*max_font_height)
> 
> As a suggestion that you can safely ignore. Maybe make max_font_glyphs a
> sysctl parameter to be able to use larger fonts ?
> 
> I get requests from time to time in kbd that it is not possible to load a
> larger font.

64KiB was really low, while the theoretically possible max was
32*32*512 = 512KB, so I understand there used to be such requests :)

Here, by setting the max to 64x128*512, I don't think we'll need more.
Even with a 8K screen (will such really exist and want a text console?)
the max 64x128 gets 128 characters on a single line, for soemthing like
36 lines. So I guess it's not worth adding yet another sysctl :)

Samuel
  
Alexey Gladkov Dec. 18, 2022, 3:25 p.m. UTC | #3
On Sun, Dec 18, 2022 at 03:55:32PM +0100, Samuel Thibault wrote:
> Hello,
> 
> Alexey Gladkov, le dim. 18 déc. 2022 15:39:38 +0100, a ecrit:
> > On Sun, Dec 18, 2022 at 01:32:12AM +0100, Samuel Thibault wrote:
> > > This moves 32x32 font size limitation checking down to drivers, so that
> > > fbcon can allow large fonts.
> > > 
> > > We still keep a limitation to 64x128 pixels so as to have a simple bounded
> > > allocation for con_font_get and in the userland kbd tool. That glyph size
> > > will however be enough to have 128x36 characters on a "16/9 8K display".
> > > 
> > > Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> > > 
> > > ---
> > > V1 -> V2: Switch con_font_get to kvmalloc/kvfree instead of kmalloc/kfree
> > > 
> > > Index: linux-6.0/drivers/tty/vt/vt.c
> > > ===================================================================
> > > --- linux-6.0.orig/drivers/tty/vt/vt.c
> > > +++ linux-6.0/drivers/tty/vt/vt.c
> > > @@ -4575,17 +4575,20 @@ void reset_palette(struct vc_data *vc)
> > >  /*
> > >   *  Font switching
> > >   *
> > > - *  Currently we only support fonts up to 32 pixels wide, at a maximum height
> > > - *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, 
> > > - *  depending on width) reserved for each character which is kinda wasty, but 
> > > - *  this is done in order to maintain compatibility with the EGA/VGA fonts. It 
> > > - *  is up to the actual low-level console-driver convert data into its favorite
> > > - *  format (maybe we should add a `fontoffset' field to the `display'
> > > - *  structure so we won't have to convert the fontdata all the time.
> > > + *  Currently we only support fonts up to 128 pixels wide, at a maximum height
> > > + *  of 128 pixels. Userspace fontdata may have to be stored with 32 bytes
> > > + *  (shorts/ints, depending on width) reserved for each character which is
> > > + *  kinda wasty, but this is done in order to maintain compatibility with the
> > > + *  EGA/VGA fonts. It is up to the actual low-level console-driver convert data
> > > + *  into its favorite format (maybe we should add a `fontoffset' field to the
> > > + *  `display' structure so we won't have to convert the fontdata all the time.
> > >   *  /Jes
> > >   */
> > >  
> > > -#define max_font_size 65536
> > > +#define max_font_width	64
> > > +#define max_font_height	128
> > > +#define max_font_glyphs	512
> > > +#define max_font_size	(max_font_glyphs*max_font_width*max_font_height)
> > 
> > As a suggestion that you can safely ignore. Maybe make max_font_glyphs a
> > sysctl parameter to be able to use larger fonts ?
> > 
> > I get requests from time to time in kbd that it is not possible to load a
> > larger font.
> 
> 64KiB was really low, while the theoretically possible max was
> 32*32*512 = 512KB, so I understand there used to be such requests :)
> 
> Here, by setting the max to 64x128*512, I don't think we'll need more.

I was not talking about the size of one glyph, but about the number of
glyphs in the font. Right now the font cannot have more than 512 glyphs.

> Even with a 8K screen (will such really exist and want a text console?)
> the max 64x128 gets 128 characters on a single line, for soemthing like
> 36 lines. So I guess it's not worth adding yet another sysctl :)

Ok.

> Samuel
>
  
Samuel Thibault Dec. 18, 2022, 3:28 p.m. UTC | #4
Alexey Gladkov, le dim. 18 déc. 2022 16:25:01 +0100, a ecrit:
> On Sun, Dec 18, 2022 at 03:55:32PM +0100, Samuel Thibault wrote:
> > Alexey Gladkov, le dim. 18 déc. 2022 15:39:38 +0100, a ecrit:
> > > On Sun, Dec 18, 2022 at 01:32:12AM +0100, Samuel Thibault wrote:
> > > > -#define max_font_size 65536
> > > > +#define max_font_width	64
> > > > +#define max_font_height	128
> > > > +#define max_font_glyphs	512
> > > > +#define max_font_size	(max_font_glyphs*max_font_width*max_font_height)
> > > 
> > > As a suggestion that you can safely ignore. Maybe make max_font_glyphs a
> > > sysctl parameter to be able to use larger fonts ?
> > > 
> > > I get requests from time to time in kbd that it is not possible to load a
> > > larger font.
> > 
> > 64KiB was really low, while the theoretically possible max was
> > 32*32*512 = 512KB, so I understand there used to be such requests :)
> > 
> > Here, by setting the max to 64x128*512, I don't think we'll need more.
> 
> I was not talking about the size of one glyph, but about the number of
> glyphs in the font. Right now the font cannot have more than 512 glyphs.

That one is unfortunately *very* hardcoded in the VT code, since it's
the very representation of the console text in vc_screenbuf which is set
to the VGA-based 16bits per glyph, with a 8+8 or 9+7 separation between
glyph number and color number. Lifting that would be way more involved.

Samuel
  
Alexey Gladkov Dec. 18, 2022, 3:38 p.m. UTC | #5
On Sun, Dec 18, 2022 at 04:28:57PM +0100, Samuel Thibault wrote:
> Alexey Gladkov, le dim. 18 déc. 2022 16:25:01 +0100, a ecrit:
> > On Sun, Dec 18, 2022 at 03:55:32PM +0100, Samuel Thibault wrote:
> > > Alexey Gladkov, le dim. 18 déc. 2022 15:39:38 +0100, a ecrit:
> > > > On Sun, Dec 18, 2022 at 01:32:12AM +0100, Samuel Thibault wrote:
> > > > > -#define max_font_size 65536
> > > > > +#define max_font_width	64
> > > > > +#define max_font_height	128
> > > > > +#define max_font_glyphs	512
> > > > > +#define max_font_size	(max_font_glyphs*max_font_width*max_font_height)
> > > > 
> > > > As a suggestion that you can safely ignore. Maybe make max_font_glyphs a
> > > > sysctl parameter to be able to use larger fonts ?
> > > > 
> > > > I get requests from time to time in kbd that it is not possible to load a
> > > > larger font.
> > > 
> > > 64KiB was really low, while the theoretically possible max was
> > > 32*32*512 = 512KB, so I understand there used to be such requests :)
> > > 
> > > Here, by setting the max to 64x128*512, I don't think we'll need more.
> > 
> > I was not talking about the size of one glyph, but about the number of
> > glyphs in the font. Right now the font cannot have more than 512 glyphs.
> 
> That one is unfortunately *very* hardcoded in the VT code, since it's
> the very representation of the console text in vc_screenbuf which is set
> to the VGA-based 16bits per glyph, with a 8+8 or 9+7 separation between
> glyph number and color number. Lifting that would be way more involved.

Yeah, but I thought that since someone decided to touch this old code,
then this someone will improve this old limit :)
  
Greg KH Jan. 19, 2023, 2:55 p.m. UTC | #6
On Sun, Dec 18, 2022 at 04:38:33PM +0100, Alexey Gladkov wrote:
> On Sun, Dec 18, 2022 at 04:28:57PM +0100, Samuel Thibault wrote:
> > Alexey Gladkov, le dim. 18 déc. 2022 16:25:01 +0100, a ecrit:
> > > On Sun, Dec 18, 2022 at 03:55:32PM +0100, Samuel Thibault wrote:
> > > > Alexey Gladkov, le dim. 18 déc. 2022 15:39:38 +0100, a ecrit:
> > > > > On Sun, Dec 18, 2022 at 01:32:12AM +0100, Samuel Thibault wrote:
> > > > > > -#define max_font_size 65536
> > > > > > +#define max_font_width	64
> > > > > > +#define max_font_height	128
> > > > > > +#define max_font_glyphs	512
> > > > > > +#define max_font_size	(max_font_glyphs*max_font_width*max_font_height)
> > > > > 
> > > > > As a suggestion that you can safely ignore. Maybe make max_font_glyphs a
> > > > > sysctl parameter to be able to use larger fonts ?
> > > > > 
> > > > > I get requests from time to time in kbd that it is not possible to load a
> > > > > larger font.
> > > > 
> > > > 64KiB was really low, while the theoretically possible max was
> > > > 32*32*512 = 512KB, so I understand there used to be such requests :)
> > > > 
> > > > Here, by setting the max to 64x128*512, I don't think we'll need more.
> > > 
> > > I was not talking about the size of one glyph, but about the number of
> > > glyphs in the font. Right now the font cannot have more than 512 glyphs.
> > 
> > That one is unfortunately *very* hardcoded in the VT code, since it's
> > the very representation of the console text in vc_screenbuf which is set
> > to the VGA-based 16bits per glyph, with a 8+8 or 9+7 separation between
> > glyph number and color number. Lifting that would be way more involved.
> 
> Yeah, but I thought that since someone decided to touch this old code,
> then this someone will improve this old limit :)

That's fine, but it would be a separate change, not this one.

thanks,

greg k-h
  

Patch

Index: linux-6.0/drivers/tty/vt/vt.c
===================================================================
--- linux-6.0.orig/drivers/tty/vt/vt.c
+++ linux-6.0/drivers/tty/vt/vt.c
@@ -4575,17 +4575,20 @@  void reset_palette(struct vc_data *vc)
 /*
  *  Font switching
  *
- *  Currently we only support fonts up to 32 pixels wide, at a maximum height
- *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, 
- *  depending on width) reserved for each character which is kinda wasty, but 
- *  this is done in order to maintain compatibility with the EGA/VGA fonts. It 
- *  is up to the actual low-level console-driver convert data into its favorite
- *  format (maybe we should add a `fontoffset' field to the `display'
- *  structure so we won't have to convert the fontdata all the time.
+ *  Currently we only support fonts up to 128 pixels wide, at a maximum height
+ *  of 128 pixels. Userspace fontdata may have to be stored with 32 bytes
+ *  (shorts/ints, depending on width) reserved for each character which is
+ *  kinda wasty, but this is done in order to maintain compatibility with the
+ *  EGA/VGA fonts. It is up to the actual low-level console-driver convert data
+ *  into its favorite format (maybe we should add a `fontoffset' field to the
+ *  `display' structure so we won't have to convert the fontdata all the time.
  *  /Jes
  */
 
-#define max_font_size 65536
+#define max_font_width	64
+#define max_font_height	128
+#define max_font_glyphs	512
+#define max_font_size	(max_font_glyphs*max_font_width*max_font_height)
 
 static int con_font_get(struct vc_data *vc, struct console_font_op *op)
 {
@@ -4595,7 +4598,7 @@  static int con_font_get(struct vc_data *
 	unsigned int vpitch = op->op == KD_FONT_OP_GET_TALL ? op->height : 32;
 
 	if (op->data) {
-		font.data = kmalloc(max_font_size, GFP_KERNEL);
+		font.data = kvmalloc(max_font_size, GFP_KERNEL);
 		if (!font.data)
 			return -ENOMEM;
 	} else
@@ -4630,7 +4633,7 @@  static int con_font_get(struct vc_data *
 		rc = -EFAULT;
 
 out:
-	kfree(font.data);
+	kvfree(font.data);
 	return rc;
 }
 
@@ -4645,9 +4648,10 @@  static int con_font_set(struct vc_data *
 		return -EINVAL;
 	if (!op->data)
 		return -EINVAL;
-	if (op->charcount > 512)
+	if (op->charcount > max_font_glyphs)
 		return -EINVAL;
-	if (op->width <= 0 || op->width > 32 || !op->height || op->height > 32)
+	if (op->width <= 0 || op->width > max_font_width || !op->height ||
+	    op->height > max_font_height)
 		return -EINVAL;
 	if (vpitch < op->height)
 		return -EINVAL;
Index: linux-6.0/drivers/usb/misc/sisusbvga/sisusb_con.c
===================================================================
--- linux-6.0.orig/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ linux-6.0/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -1203,7 +1203,7 @@  sisusbcon_font_set(struct vc_data *c, st
 	struct sisusb_usb_data *sisusb;
 	unsigned charcount = font->charcount;
 
-	if (font->width != 8 || vpitch != 32 ||
+	if (font->width != 8 || font->height > 32 || vpitch != 32 ||
 	    (charcount != 256 && charcount != 512))
 		return -EINVAL;
 
Index: linux-6.0/drivers/video/console/vgacon.c
===================================================================
--- linux-6.0.orig/drivers/video/console/vgacon.c
+++ linux-6.0/drivers/video/console/vgacon.c
@@ -1037,7 +1037,7 @@  static int vgacon_font_set(struct vc_dat
 	if (vga_video_type < VIDEO_TYPE_EGAM)
 		return -EINVAL;
 
-	if (font->width != VGA_FONTWIDTH || vpitch != 32 ||
+	if (font->width != VGA_FONTWIDTH || font->height > 32 || vpitch != 32 ||
 	    (charcount != 256 && charcount != 512))
 		return -EINVAL;
 
Index: linux-6.0/drivers/video/fbdev/core/fbcon.c
===================================================================
--- linux-6.0.orig/drivers/video/fbdev/core/fbcon.c
+++ linux-6.0/drivers/video/fbdev/core/fbcon.c
@@ -2279,6 +2279,8 @@  static int fbcon_get_font(struct vc_data
 
 	font->width = vc->vc_font.width;
 	font->height = vc->vc_font.height;
+	if (font->height > vpitch)
+		return -ENOSPC;
 	font->charcount = vc->vc_hi_font_mask ? 512 : 256;
 	if (!font->data)
 		return 0;