Skip to content

Commit 2a24830

Browse files
committed
vgacon/vt: clear buffer attributes when we load a 512 character font (v2)
When we switch from 256->512 byte font rendering mode, it means the current contents of the screen is being reinterpreted. The bit that holds the high bit of the 9-bit font, may have been previously set, and thus the new font misrenders. The problem case we see is grub2 writes spaces with the bit set, so it ends up with data like 0x820, which gets reinterpreted into 0x120 char which the font translates into G with a circumflex. This flashes up on screen at boot and is quite ugly. A current side effect of this patch though is that any rendering on the screen changes color to a slightly darker color, but at least the screen no longer corrupts. v2: as suggested by hpa, always clear the attribute space, whether we are are going to or from 512 chars. Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie <airlied@redhat.com>
1 parent 1589a3e commit 2a24830

File tree

3 files changed

+17
-8
lines changed

3 files changed

+17
-8
lines changed

drivers/tty/vt/vt.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ static inline void save_screen(struct vc_data *vc)
638638
* Redrawing of screen
639639
*/
640640

641-
static void clear_buffer_attributes(struct vc_data *vc)
641+
void clear_buffer_attributes(struct vc_data *vc)
642642
{
643643
unsigned short *p = (unsigned short *)vc->vc_origin;
644644
int count = vc->vc_screenbuf_size / 2;

drivers/video/console/vgacon.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,7 +1064,7 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
10641064
unsigned short video_port_status = vga_video_port_reg + 6;
10651065
int font_select = 0x00, beg, i;
10661066
char *charmap;
1067-
1067+
bool clear_attribs = false;
10681068
if (vga_video_type != VIDEO_TYPE_EGAM) {
10691069
charmap = (char *) VGA_MAP_MEM(colourmap, 0);
10701070
beg = 0x0e;
@@ -1169,12 +1169,6 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
11691169

11701170
/* if 512 char mode is already enabled don't re-enable it. */
11711171
if ((set) && (ch512 != vga_512_chars)) {
1172-
/* attribute controller */
1173-
for (i = 0; i < MAX_NR_CONSOLES; i++) {
1174-
struct vc_data *c = vc_cons[i].d;
1175-
if (c && c->vc_sw == &vga_con)
1176-
c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
1177-
}
11781172
vga_512_chars = ch512;
11791173
/* 256-char: enable intensity bit
11801174
512-char: disable intensity bit */
@@ -1185,8 +1179,22 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
11851179
it means, but it works, and it appears necessary */
11861180
inb_p(video_port_status);
11871181
vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);
1182+
clear_attribs = true;
11881183
}
11891184
raw_spin_unlock_irq(&vga_lock);
1185+
1186+
if (clear_attribs) {
1187+
for (i = 0; i < MAX_NR_CONSOLES; i++) {
1188+
struct vc_data *c = vc_cons[i].d;
1189+
if (c && c->vc_sw == &vga_con) {
1190+
/* force hi font mask to 0, so we always clear
1191+
the bit on either transition */
1192+
c->vc_hi_font_mask = 0x00;
1193+
clear_buffer_attributes(c);
1194+
c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
1195+
}
1196+
}
1197+
}
11901198
return 0;
11911199
}
11921200

include/linux/vt_kern.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ int con_set_cmap(unsigned char __user *cmap);
4747
int con_get_cmap(unsigned char __user *cmap);
4848
void scrollback(struct vc_data *vc, int lines);
4949
void scrollfront(struct vc_data *vc, int lines);
50+
void clear_buffer_attributes(struct vc_data *vc);
5051
void update_region(struct vc_data *vc, unsigned long start, int count);
5152
void redraw_screen(struct vc_data *vc, int is_switch);
5253
#define update_screen(x) redraw_screen(x, 0)

0 commit comments

Comments
 (0)