Hello, Karl.

Thanks for the reply.

On Fri, Apr 02, 2021 at 21:32:04 +0200, k...@aspodata.se wrote:
> Alan Mackenzie:
> ...
> > I've now cobbled together a working console scroll on Linux
> > 5.4.80-gentoo-r1.  In the end, I reused much of the old machinery which
> > was still present in 4.19.97.  Once I've tidied it up, I hope that the
> > resulting patch file will apply cleanly also to later versions than
> > 5.4.80-r1.
> ...

> Nice, where is the patch so I can try ?

I've attached a patch to this post.  To apply it, the following seems to
work from the top directory of a kernel source tree, e.g. 5.4.80-r1:

    $ patch -p0 < diff.20210402.diff

..  Then you'll need to run make menuconfig (or whatever), going down to
Device Drivers/Graphic support/Console display driver support and there
accepting the defaults for the new config variables.  (This is assuming
you've got FRAMEBUFFER support enabled in a neighbouring page.)

Then build the kernel as normal, and put the new version into whatever
boot loader you use.  It should (??) run, with a scrollback buffer on
each virtual terminal.

Just a word about the current state of the source - it is rough, with
things unfinished.  The "word" STOUGH (pronounced "stuff") is just a
word I use which appears nowhere else and enables me to find changes
quickly and unambiguously.

As I said, I'm not finished with the changes, and swapping from and back
to a scrolled tty isn't completely satisfactory.  Nevertheless, I hope
it works for you and you have fun with it.

> > (i) The scrolling doesn't work on /dev/tty1 aka the console.
> > (ii) When, e.g., /dev/tty6 has been scrolled upwards a bit, and then
> >   <Alt><F2> pressed to go to /dev/tty2, on returning to /dev/tty6, the
> >   scrolling has been cancelled and the cursor is no longer visible.
> >   However, the scrollback buffer is still present.
> > 
> > I think I'm fairly likely to be able to solve (ii).  However, (i), the
> > problem with /dev/tty1, has me baffled.  I don't know where to start
> > looking for the problem.  If anybody with some kernel knowledge could
> > make any suggestions, I'd be very grateful.

> What happens if you set /dev/console to be /dev/ttyS0, i.e. make sure 
> that tty1 is the only one using the first virtual console.

I will try than.  Thanks!

> Regards,
> /Karl Hammar

-- 
Alan Mackenzie (Nuremberg, Germany).

--- 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, &param);
 
+        /* 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,

Reply via email to