--- drivers/video/console/Kconfig.orig 2021-03-31 19:14:48.186140856 +0000 +++ drivers/video/console/Kconfig 2021-03-31 12:39:08.090301096 +0000 @@ -79,6 +79,52 @@ help Low-level framebuffer-based console driver. +config FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK + bool "Enable Scrollback Buffer in System RAM" + depends on FB=y && FRAMEBUFFER_CONSOLE + default y + help + This option creates scrollback buffers for each framebuffer console, + or one buffer for them all. These buffers are allocated dynamically + during initialisation. + + If you want this feature, say 'Y' here and enter the amount of + RAM to allocate for this buffer. If unsure, say 'N'. + +config FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_SIZE + int "Scrollback Buffer Size (in KB)" + depends on FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK + range 1 1024 + default "128" + help + Enter the amount of System RAM to allocate for scrollback buffers of + framebuffer consoles. Each character position on the video takes 2 + bytes of storage. 128k will give you approximately 4 240x67 + screenfuls of scrollback buffer. + +config FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_PERSISTENT_ENABLE_BY_DEFAULT + bool "Persistent Scrollback History for each framebuffer console by default" + depends on FB=y && FRAMEBUFFER_CONSOLE && FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK + default y + help + + Say Y here if the scrollback history should persist by default when + switching between consoles. Otherwise, the scrollback history will + be flushed the first time a scroll-up operation occurs on the new + console after the console is switched. STOUGH!!! FIXME!!! This + feature can also be enabled using the boot command line parameter + 'vgacon.scrollback_persistent=1'. + + This feature might break your tool of choice to flush the scrollback + buffer, e.g. clear(1) will work fine but Debian's clear_console(1) + will be broken, which might cause security issues. + You can use the escape sequence \e[3J instead if this feature is + activated. + + Note that a buffer of VGACON_SOFT_SCROLLBACK_SIZE is taken for each + created tty device. + So if you use a RAM-constrained system, say N here. + config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY bool "Map the console to the primary display device" depends on FRAMEBUFFER_CONSOLE --- drivers/tty/vt/vt.orig.c 2020-11-28 17:14:38.523649992 +0000 +++ drivers/tty/vt/vt.c 2021-04-02 15:28:53.094607272 +0000 @@ -142,6 +142,13 @@ #define DEFAULT_BELL_DURATION (HZ/8) #define DEFAULT_CURSOR_BLINK_MS 200 +/* NEW STOUGH, 2021-04-01 */ +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK +static unsigned int console_soft_scrollback_size = + 1024 * CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK_SIZE; +#endif +/* END OF NEW STOUGH */ + struct vc vc_cons [MAX_NR_CONSOLES]; #ifndef VT_SINGLE_DRIVER @@ -623,6 +630,205 @@ } } +/* NEW STOUGH, 2021-03-31 */ +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK +/* NEW STOUGH, 2021-04-01 */ +static void con_update_softback(struct vc_data *vc) +{ + int l = vc->vc_softback_size / vc->vc_size_row; + + if (l > 5) + vc->vc_softback_end = vc->vc_softback_buf + l * vc->vc_size_row; + else + /* Smaller scrollback makes no sense, and 0 would screw + the operation totally */ + vc->vc_softback_top = 0; +} + +static int concon_set_origin(struct vc_data *vc) +{ + if (vc->vc_softback_lines) + concon_scrolldelta(vc, vc->vc_softback_lines); + return 0; +} +/* END OF NEW STOUGH */ + +#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) + +static void con_redraw_softback(struct vc_data *vc, /* struct display *p, */ + long delta) +{ + int count = vc->vc_rows; + unsigned short *d, *s; + unsigned long n; + int line = 0; + + d = (u16 *) vc->vc_softback_curr; + if (d == (u16 *) vc->vc_softback_in) + d = (u16 *) vc->vc_origin; + n = vc->vc_softback_curr + delta * vc->vc_size_row; + vc->vc_softback_lines -= delta; + if (delta < 0) { + if (vc->vc_softback_curr < vc->vc_softback_top + && n < vc->vc_softback_buf) { + n += vc->vc_softback_end - vc->vc_softback_buf; + if (n < vc->vc_softback_top) { + vc->vc_softback_lines -= + (vc->vc_softback_top - n) / vc->vc_size_row; + n = vc->vc_softback_top; + } + } else if (vc->vc_softback_curr >= vc->vc_softback_top + && n < vc->vc_softback_top) { + vc->vc_softback_lines -= + (vc->vc_softback_top - n) / vc->vc_size_row; + n = vc->vc_softback_top; + } + } else { + if (vc->vc_softback_curr > vc->vc_softback_in + && n >= vc->vc_softback_end) { + n += vc->vc_softback_buf - vc->vc_softback_end; + if (n > vc->vc_softback_in) { + n = vc->vc_softback_in; + vc->vc_softback_lines = 0; + } + } else if (vc->vc_softback_curr <= vc->vc_softback_in + && n > vc->vc_softback_in) { + n = vc->vc_softback_in; + vc->vc_softback_lines = 0; + } + } + if (n == vc->vc_softback_curr) + return; + vc->vc_softback_curr = n; + s = (u16 *) vc->vc_softback_curr; + if (s == (u16 *) vc->vc_softback_in) + s = (u16 *) vc->vc_origin; + while (count--) { + unsigned short *start; + unsigned short *le; + unsigned short c; + int x = 0; + unsigned short attr = 1; + + start = s; + le = advance_row(s, 1); + do { + c = scr_readw(s); + if (attr != (c & 0xff00)) { + attr = c & 0xff00; + if (s > start) { + vc->vc_sw->con_putcs( + vc, start, s - start, + line, x); + x += s - start; + start = s; + } + } + if (c == scr_readw(d)) { + if (s > start) { + vc->vc_sw->con_putcs( + vc, start, s - start, + line, x); + x += s - start + 1; + start = s + 1; + } else { + x++; + start++; + } + } + s++; + d++; + } while (s < le); + if (s > start) + vc->vc_sw->con_putcs(vc, start, s - start, line, x); + line++; + if (d == (u16 *) vc->vc_softback_end) + d = (u16 *) vc->vc_softback_buf; + if (d == (u16 *) vc->vc_softback_in) + d = (u16 *) vc->vc_origin; + if (s == (u16 *) vc->vc_softback_end) + s = (u16 *) vc->vc_softback_buf; + if (s == (u16 *) vc->vc_softback_in) + s = (u16 *) vc->vc_origin; + } +} +/* END OF NEW STOUGH */ + +/* NEW STOUGH, 2021-04-01 */ +static inline void con_softback_note(struct vc_data *vc, int t, + int count) +{ + unsigned short *p; + + if (vc->vc_num != fg_console) + return; + p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row); + + while (count) { + scr_memcpyw((u16 *) vc->vc_softback_in, p, vc->vc_size_row); + count--; + p = advance_row(p, 1); + vc->vc_softback_in += vc->vc_size_row; + if (vc->vc_softback_in == vc->vc_softback_end) + vc->vc_softback_in = vc->vc_softback_buf; + if (vc->vc_softback_in == vc->vc_softback_top) { + vc->vc_softback_top += vc->vc_size_row; + if (vc->vc_softback_top == vc->vc_softback_end) + vc->vc_softback_top = vc->vc_softback_buf; + } + } + vc->vc_softback_curr = vc->vc_softback_in; +} + +void concon_scrolldelta(struct vc_data *vc, int lines) +{ + /* struct display *disp = &fb_display[fg_console]; */ + /* int offset, limit, scrollback_old; */ + + if (vc->vc_softback_top) { + if (vc->vc_num != fg_console) + return; + if (vc->vc_mode != KD_TEXT || !lines) + return; +#if 0 + if (logo_shown >= 0) { + struct vc_data *conp2 = vc_cons[logo_shown].d; + + if (conp2->vc_top == logo_lines + && conp2->vc_bottom == conp2->vc_rows) + conp2->vc_top = 0; + if (logo_shown == vc->vc_num) { + unsigned long p, q; + int i; + + p = vc->vc_softback_in; + q = vc->vc_origin + + logo_lines * vc->vc_size_row; + for (i = 0; i < logo_lines; i++) { + if (p == vc->vc_softback_top) + break; + if (p == vc->vc_softback_buf) + p = vc->vc_softback_end; + p -= vc->vc_size_row; + q -= vc->vc_size_row; + scr_memcpyw((u16 *) q, (u16 *) p, + vc->vc_size_row); + } + vc->vc_softback_in = vc->vc_softback_curr = p; + update_region(vc, vc->vc_origin, + logo_lines * vc->vc_cols); + } + logo_shown = FBCON_LOGO_CANSHOW; + } +#endif + vc->vc_sw->con_cursor(vc, CM_ERASE /* | CM_SOFTBACK */); + con_redraw_softback(vc, /* disp, */ lines); + vc->vc_sw->con_cursor(vc, CM_DRAW /* | CM_SOFTBACK */); + } +} + +/* END OF NEW STOUGH */ +#endif /* CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK */ static void con_scroll(struct vc_data *vc, unsigned int t, unsigned int b, enum con_scroll dir, unsigned int nr) @@ -633,6 +839,12 @@ nr = b - t - 1; if (b > vc->vc_rows || t >= b || nr < 1) return; + /* NEW STOUGH, 2021-04-01 */ +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK + if (dir == SM_UP && vc->vc_softback_top) + con_softback_note (vc, t, nr); +#endif + /* END OF NEW STOUGH */ vc_uniscr_scroll(vc, t, b, dir, nr); if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, dir, nr)) return; @@ -900,6 +1112,10 @@ clear_selection(); vc->vc_sw->con_cursor(vc, CM_ERASE); + /* NEW STOUGH, 2021-04-01 */ + /* if (vc->vc_softback_lines) */ + /* concon_set_origin (vc); */ + /* END OF NEW STOUGH */ hide_softcursor(vc); } @@ -912,7 +1128,15 @@ clear_selection(); add_softcursor(vc); if ((vc->vc_cursor_type & 0x0f) != 1) - vc->vc_sw->con_cursor(vc, CM_DRAW); + /* NEW STOUGH, 2021-04-01 */ + { + /* if (vc->vc_softback_lines) */ + /* concon_set_origin (vc); */ + /* END OF NEW STOUGH */ + vc->vc_sw->con_cursor(vc, CM_DRAW); + /* NEW STOUGH, 2021-04-01 */ + } + /* END OF NEW STOUGH */ } else hide_cursor(vc); } @@ -922,8 +1146,19 @@ WARN_CONSOLE_UNLOCKED(); if (!con_is_visible(vc) || - !vc->vc_sw->con_set_origin || - !vc->vc_sw->con_set_origin(vc)) + /* NEW STOUGH, 2021-04-01 */ +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK + ( + !concon_set_origin (vc) && + ( +#endif + /* END OF NEW STOUGH */ + !vc->vc_sw->con_set_origin || + !vc->vc_sw->con_set_origin(vc) +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK + )) +#endif + ) vc->vc_origin = (unsigned long)vc->vc_screenbuf; vc->vc_visible_origin = vc->vc_origin; vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size; @@ -998,7 +1233,9 @@ hide_cursor(old_vc); if (!con_is_visible(old_vc)) { save_screen(old_vc); - set_origin(old_vc); + /* OLD STOUGH, 2021-04-02 */ + /* set_origin(old_vc); */ + /* END OF OLD STOUGH */ } if (tty0dev) sysfs_notify(&tty0dev->kobj, NULL, "active"); @@ -1011,7 +1248,9 @@ int update; int old_was_color = vc->vc_can_do_color; - set_origin(vc); + /* OLD STOUGH, 2021-04-02 */ + /* set_origin(vc); */ + /* END OF OLD STOUGH */ update = vc->vc_sw->con_switch(vc); set_palette(vc); /* @@ -1152,6 +1391,20 @@ vcs_make_sysfs(currcons); atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, ¶m); + /* NEW STOUGH, 2021-04-01 */ +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK + vc->vc_softback_size = console_soft_scrollback_size; + err = -ENOMEM; + vc->vc_softback_buf = + (unsigned long)kzalloc(vc->vc_softback_size, GFP_KERNEL); + if (!vc->vc_softback_buf) + goto err_free; + vc->vc_softback_in = vc->vc_softback_top = vc->vc_softback_curr = + vc->vc_softback_buf; + vc->vc_softback_lines = 0; + con_update_softback(vc); +#endif + /* END OF NEW STOUGH */ return 0; err_free: visual_deinit(vc); --- include/linux/console_struct.h.orig 2021-04-02 19:55:52.696177657 +0000 +++ include/linux/console_struct.h 2021-04-02 14:30:20.792800814 +0000 @@ -70,6 +70,18 @@ unsigned short *vc_screenbuf; /* In-memory character/attribute buffer */ unsigned int vc_screenbuf_size; unsigned char vc_mode; /* KD_TEXT, ... */ + /* NEW STOUGH, 2021-03-31 */ +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK + unsigned int vc_softback_size; /* Size in bytes of scrollback buffer. */ + unsigned long vc_softback_buf; /* Address of scrollback buffer. */ + unsigned long vc_softback_end; /* (Just past) end of buffer. */ + unsigned long vc_softback_in; /* Head pointer into circular buffer. */ + unsigned long vc_softback_top; /* Tail pointer into circular buffer. */ + unsigned long vc_softback_curr; /* Pos in vc_screenbuf or vc_softback_buf + corresponding to visible screen. */ + int vc_softback_lines; /* Number of lines currently scrolled. */ +#endif + /* END OF NEW STOUGH */ /* attributes for all characters on screen */ unsigned char vc_attr; /* Current attributes */ unsigned char vc_def_color; /* Default colors */ --- drivers/video/fbdev/core/fbcon.c.orig 2021-04-02 19:58:46.332168089 +0000 +++ drivers/video/fbdev/core/fbcon.c 2021-04-02 00:11:10.090444550 +0000 @@ -1337,6 +1337,11 @@ else fbcon_add_cursor_timer(info); + /* NEW STOUGH, 2021-04-01 */ + if (vc->vc_softback_lines) + mode = CM_ERASE; + /* END OF NEW STOUGH */ + ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1; ops->cursor(vc, info, mode, get_color(vc, info, c, 1), @@ -3115,6 +3120,11 @@ .con_font_default = fbcon_set_def_font, .con_font_copy = fbcon_copy_font, .con_set_palette = fbcon_set_palette, + /* NEW STOUGH, 2021-04-01 */ +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK + .con_scrolldelta = concon_scrolldelta, +#endif + /* END OF NEW STOUGH */ .con_set_origin = fbcon_set_origin, .con_invert_region = fbcon_invert_region, .con_screen_pos = fbcon_screen_pos, --- include/linux/vt_kern.h.orig 2021-04-02 20:01:19.552159645 +0000 +++ include/linux/vt_kern.h 2021-04-01 17:31:45.125471834 +0000 @@ -129,6 +129,11 @@ /* vt.c */ void vt_event_post(unsigned int event, unsigned int old, unsigned int new); int vt_waitactive(int n); +/* NEW STOUGH, 2021-04-01 */ +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_SOFT_SCROLLBACK +void concon_scrolldelta(struct vc_data *vc, int lines); +#endif +/* END OF NEW STOUGH */ void change_console(struct vc_data *new_vc); void reset_vc(struct vc_data *vc); extern int do_unbind_con_driver(const struct consw *csw, int first, int last,