Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 22 Sep 2014 16:13:33 +0000 (UTC)
From:      Jean-Sebastien Pedron <dumbbell@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r271973 - stable/10/sys/dev/vt
Message-ID:  <201409221613.s8MGDXWs076126@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: dumbbell
Date: Mon Sep 22 16:13:33 2014
New Revision: 271973
URL: http://svnweb.freebsd.org/changeset/base/271973

Log:
  vt(4): Merge several bug fixes and improvements
  
  SVN revisions in this MFC:
    271756 271758 271868 271871 271872 271899
  
  Detailed commit list:
  
  r271756:
    vt(4): Fix out-of-bounds array access in VT_ACTIVATE ioctl handling
  
    CID:		1229964
  
  r271758
    vt(4): Use strncpy() to copy into a fixed-size buffer
  
    CID:		1230007
  
  r271868:
    vt(4): Remove vt_buf->vb_dirtymask
  
    This structure and the associated functions were unused since the
    implementation of vd_bitblt_text_t callbacks.
  
  r271871:
    vt(4): Rewrite history scrolling
  
    It's now possible to scroll up the 500 hard-coded lines of history, not
    just a fraction of them. For instance, one can reach the top of the boot
    process.
  
    Sometimes, when scrolling or when changing the screen size (by changing
    the font or loading a KMS driver for instance), one could see the
    history cycling (old content appeared below latest lines). This is
    fixed.
  
    Now, when the resolution changes are more lines can be shown, the
    displayed area is adjusted so that, if the screen was filled with
    content before, it's filled with content after as well: more history
    is visible, instead of having blank lines below the previously visible
    content.
  
  r271872:
    vt(4): Remove superfluous word in comment
  
    Submitted by:	brueffer@
  
  r271899:
    Make gcc happy by initialising the variable only set in a couple of
    case statements without a default.
  
  Approved by:	re (marius)

Modified:
  stable/10/sys/dev/vt/vt.h
  stable/10/sys/dev/vt/vt_buf.c
  stable/10/sys/dev/vt/vt_core.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/vt/vt.h
==============================================================================
--- stable/10/sys/dev/vt/vt.h	Mon Sep 22 16:09:18 2014	(r271972)
+++ stable/10/sys/dev/vt/vt.h	Mon Sep 22 16:13:33 2014	(r271973)
@@ -173,11 +173,6 @@ struct vt_device {
  * been modified.
  */
 
-struct vt_bufmask {
-	uint64_t		 vbm_row, vbm_col;
-#define	VBM_DIRTY		UINT64_MAX
-};
-
 struct vt_buf {
 	struct mtx		 vb_lock;	/* Buffer lock. */
 	term_pos_t		 vb_scr_size;	/* (b) Screen dimensions. */
@@ -196,7 +191,6 @@ struct vt_buf {
 	term_pos_t		 vb_mark_end;	/* (b) Copy region end. */
 	int			 vb_mark_last;	/* Last mouse event. */
 	term_rect_t		 vb_dirtyrect;	/* (b) Dirty rectangle. */
-	struct vt_bufmask	 vb_dirtymask;	/* (b) Dirty bitmasks. */
 	term_char_t		*vb_buffer;	/* (u) Data buffer. */
 	term_char_t		**vb_rows;	/* (u) Array of rows */
 };
@@ -210,7 +204,7 @@ void vtbuf_putchar(struct vt_buf *, cons
 void vtbuf_cursor_position(struct vt_buf *, const term_pos_t *);
 void vtbuf_scroll_mode(struct vt_buf *vb, int yes);
 void vtbuf_dirty(struct vt_buf *vb, const term_rect_t *area);
-void vtbuf_undirty(struct vt_buf *, term_rect_t *, struct vt_bufmask *);
+void vtbuf_undirty(struct vt_buf *, term_rect_t *);
 void vtbuf_sethistory_size(struct vt_buf *, int);
 int vtbuf_iscursor(const struct vt_buf *vb, int row, int col);
 void vtbuf_cursor_visibility(struct vt_buf *, int);

Modified: stable/10/sys/dev/vt/vt_buf.c
==============================================================================
--- stable/10/sys/dev/vt/vt_buf.c	Mon Sep 22 16:09:18 2014	(r271972)
+++ stable/10/sys/dev/vt/vt_buf.c	Mon Sep 22 16:13:33 2014	(r271973)
@@ -76,44 +76,47 @@ vthistory_seek(struct vt_buf *vb, int of
 		}
 		return (0); /* No changes */
 	}
-	top = (vb->vb_flags & VBF_HISTORY_FULL)?
-	    (vb->vb_curroffset + vb->vb_scr_size.tp_row):vb->vb_history_size;
-	bottom = vb->vb_curroffset + vb->vb_history_size;
 
-	/*
-	 * Operate on copy of offset value, since it temporary can be bigger
-	 * than amount of rows in buffer.
-	 */
-	roffset = vb->vb_roffset + vb->vb_history_size;
+	/* "top" may be a negative integer. */
+	bottom = vb->vb_curroffset;
+	top = (vb->vb_flags & VBF_HISTORY_FULL) ?
+	    bottom + vb->vb_scr_size.tp_row - vb->vb_history_size :
+	    0;
+
+	roffset = 0; /* Make gcc happy. */
 	switch (whence) {
 	case VHS_SET:
-		roffset = offset + vb->vb_history_size;
+		if (offset < 0)
+			offset = 0;
+		roffset = top + offset;
 		break;
 	case VHS_CUR:
+		/*
+		 * Operate on copy of offset value, since it temporary
+		 * can be bigger than amount of rows in buffer.
+		 */
+		roffset = vb->vb_roffset;
+		if (roffset >= bottom + vb->vb_scr_size.tp_row)
+			roffset -= vb->vb_history_size;
+
 		roffset += offset;
+		roffset = MAX(roffset, top);
+		roffset = MIN(roffset, bottom);
+
+		if (roffset < 0)
+			roffset = vb->vb_history_size + roffset;
+
 		break;
 	case VHS_END:
 		/* Go to current offset. */
-		roffset = vb->vb_curroffset + vb->vb_history_size;
+		roffset = vb->vb_curroffset;
 		break;
 	}
 
-	roffset = (roffset < top)?top:roffset;
-	roffset = (roffset > bottom)?bottom:roffset;
+	diff = vb->vb_roffset != roffset;
+	vb->vb_roffset = roffset;
 
-	roffset %= vb->vb_history_size;
-
-	if (vb->vb_roffset != roffset) {
-		diff = vb->vb_roffset - roffset;
-		vb->vb_roffset = roffset;
-		/*
-		 * Offset changed, please update Nth lines on sceen.
-		 * +N - Nth lines at top;
-		 * -N - Nth lines at bottom.
-		 */
-		return (diff);
-	}
-	return (0); /* No changes */
+	return (diff);
 }
 
 void
@@ -123,6 +126,8 @@ vthistory_addlines(struct vt_buf *vb, in
 	vb->vb_curroffset += offset;
 	if (vb->vb_curroffset < 0)
 		vb->vb_curroffset = 0;
+	if (vb->vb_curroffset + vb->vb_scr_size.tp_row >= vb->vb_history_size)
+		vb->vb_flags |= VBF_HISTORY_FULL;
 	vb->vb_curroffset %= vb->vb_history_size;
 	if ((vb->vb_flags & VBF_SCROLL) == 0) {
 		vb->vb_roffset = vb->vb_curroffset;
@@ -195,39 +200,6 @@ vtbuf_iscursor(const struct vt_buf *vb, 
 	return (0);
 }
 
-static inline uint64_t
-vtbuf_dirty_axis(unsigned int begin, unsigned int end)
-{
-	uint64_t left, right, mask;
-
-	/*
-	 * Mark all bits between begin % 64 and end % 64 dirty.
-	 * This code is functionally equivalent to:
-	 *
-	 * 	for (i = begin; i < end; i++)
-	 * 		mask |= (uint64_t)1 << (i % 64);
-	 */
-
-	/* Obvious case. Mark everything dirty. */
-	if (end - begin >= 64)
-		return (VBM_DIRTY);
-
-	/* 1....0; used bits on the left. */
-	left = VBM_DIRTY << begin % 64;
-	/* 0....1; used bits on the right. */
-	right = VBM_DIRTY >> -end % 64;
-
-	/*
-	 * Only take the intersection.  If the result of that is 0, it
-	 * means that the selection crossed a 64 bit boundary along the
-	 * way, which means we have to take the complement.
-	 */
-	mask = left & right;
-	if (mask == 0)
-		mask = left | right;
-	return (mask);
-}
-
 static inline void
 vtbuf_dirty_locked(struct vt_buf *vb, const term_rect_t *area)
 {
@@ -240,10 +212,6 @@ vtbuf_dirty_locked(struct vt_buf *vb, co
 		vb->vb_dirtyrect.tr_end.tp_row = area->tr_end.tp_row;
 	if (vb->vb_dirtyrect.tr_end.tp_col < area->tr_end.tp_col)
 		vb->vb_dirtyrect.tr_end.tp_col = area->tr_end.tp_col;
-	vb->vb_dirtymask.vbm_row |=
-	    vtbuf_dirty_axis(area->tr_begin.tp_row, area->tr_end.tp_row);
-	vb->vb_dirtymask.vbm_col |=
-	    vtbuf_dirty_axis(area->tr_begin.tp_col, area->tr_end.tp_col);
 }
 
 void
@@ -272,16 +240,14 @@ vtbuf_make_undirty(struct vt_buf *vb)
 
 	vb->vb_dirtyrect.tr_begin = vb->vb_scr_size;
 	vb->vb_dirtyrect.tr_end.tp_row = vb->vb_dirtyrect.tr_end.tp_col = 0;
-	vb->vb_dirtymask.vbm_row = vb->vb_dirtymask.vbm_col = 0;
 }
 
 void
-vtbuf_undirty(struct vt_buf *vb, term_rect_t *r, struct vt_bufmask *m)
+vtbuf_undirty(struct vt_buf *vb, term_rect_t *r)
 {
 
 	VTBUF_LOCK(vb);
 	*r = vb->vb_dirtyrect;
-	*m = vb->vb_dirtymask;
 	vtbuf_make_undirty(vb);
 	VTBUF_UNLOCK(vb);
 }
@@ -453,71 +419,155 @@ vtbuf_sethistory_size(struct vt_buf *vb,
 void
 vtbuf_grow(struct vt_buf *vb, const term_pos_t *p, unsigned int history_size)
 {
-	term_char_t *old, *new, **rows, **oldrows, **copyrows, *row;
-	int bufsize, rowssize, w, h, c, r;
+	term_char_t *old, *new, **rows, **oldrows, **copyrows, *row, *oldrow;
+	int bufsize, rowssize, w, h, c, r, history_was_full;
+	unsigned int old_history_size;
 	term_rect_t rect;
 
 	history_size = MAX(history_size, p->tp_row);
 
-	/* If new screen/history size bigger or buffer is VBF_STATIC. */
-	if ((history_size > vb->vb_history_size) || (p->tp_col >
-	    vb->vb_scr_size.tp_col) || (vb->vb_flags & VBF_STATIC)) {
-		/* Allocate new buffer. */
-		bufsize = history_size * p->tp_col * sizeof(term_char_t);
-		new = malloc(bufsize, M_VTBUF, M_WAITOK | M_ZERO);
-		rowssize = history_size * sizeof(term_pos_t *);
-		rows = malloc(rowssize, M_VTBUF, M_WAITOK | M_ZERO);
+	/* Allocate new buffer. */
+	bufsize = history_size * p->tp_col * sizeof(term_char_t);
+	new = malloc(bufsize, M_VTBUF, M_WAITOK | M_ZERO);
+	rowssize = history_size * sizeof(term_pos_t *);
+	rows = malloc(rowssize, M_VTBUF, M_WAITOK | M_ZERO);
 
-		/* Toggle it. */
-		VTBUF_LOCK(vb);
-		old = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_buffer;
-		oldrows = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_rows;
-		copyrows = vb->vb_rows;
-		w = vb->vb_scr_size.tp_col;
-		h = vb->vb_history_size;
-
-		vb->vb_history_size = history_size;
-		vb->vb_buffer = new;
-		vb->vb_rows = rows;
-		vb->vb_flags &= ~VBF_STATIC;
-		vb->vb_scr_size = *p;
-		vtbuf_init_rows(vb);
+	/* Toggle it. */
+	VTBUF_LOCK(vb);
+	old = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_buffer;
+	oldrows = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_rows;
+	copyrows = vb->vb_rows;
+
+	w = vb->vb_scr_size.tp_col;
+	h = vb->vb_scr_size.tp_row;
+	old_history_size = vb->vb_history_size;
+	history_was_full = vb->vb_flags & VBF_HISTORY_FULL;
+
+	vb->vb_history_size = history_size;
+	vb->vb_buffer = new;
+	vb->vb_rows = rows;
+	vb->vb_flags &= ~VBF_STATIC;
+	vb->vb_scr_size = *p;
+	vtbuf_init_rows(vb);
+
+	/* Copy history and fill extra space if needed. */
+	if (history_size > old_history_size) {
+		/*
+		 * Copy rows to the new buffer. The first row in the history
+		 * is back to index 0, ie. the new buffer doesn't cycle.
+		 *
+		 * The rest of the new buffer is initialized with blank
+		 * content.
+		 */
+		for (r = 0; r < old_history_size; r ++) {
+			row = rows[r];
+
+			/* Compute the corresponding row in the old buffer. */
+			if (history_was_full)
+				/*
+				 * The buffer is full, the "top" row is
+				 * the one just after the viewable area
+				 * (curroffset + viewable height) in the
+				 * cycling buffer. The corresponding row
+				 * is computed from this top row.
+				 */
+				oldrow = copyrows[
+				    (vb->vb_curroffset + h + r) %
+				    old_history_size];
+			else
+				/*
+				 * The buffer is not full, therefore,
+				 * we didn't cycle already. The
+				 * corresponding rows are the same in
+				 * both buffers.
+				 */
+				oldrow = copyrows[r];
+
+			memmove(row, oldrow,
+			    MIN(p->tp_col, w) * sizeof(term_char_t));
 
-		/* Copy history and fill extra space. */
-		for (r = 0; r < history_size; r ++) {
 			/*
 			 * XXX VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR) will
 			 * extended lines of kernel text using the wrong
 			 * background color.
 			 */
-			row = rows[r];
-			if (r < h) { /* Copy. */
-				memmove(rows[r], copyrows[r],
-				    MIN(p->tp_col, w) * sizeof(term_char_t));
-				for (c = MIN(p->tp_col, w); c < p->tp_col;
-				    c++) {
-					row[c] = VTBUF_SPACE_CHAR(
-					    TERMINAL_NORM_ATTR);
-				}
-			} else { /* Just fill. */
-				rect.tr_begin.tp_col = 0;
-				rect.tr_begin.tp_row = r;
-				rect.tr_end.tp_col = p->tp_col;
-				rect.tr_end.tp_row = p->tp_row;
-				vtbuf_fill(vb, &rect,
-				    VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR));
-				break;
+			for (c = MIN(p->tp_col, w); c < p->tp_col; c++) {
+				row[c] = VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR);
 			}
 		}
-		vtbuf_make_undirty(vb);
-		VTBUF_UNLOCK(vb);
-		/* Deallocate old buffer. */
-		free(old, M_VTBUF);
-		free(oldrows, M_VTBUF);
+
+		/* Fill remaining rows. */
+		rect.tr_begin.tp_col = 0;
+		rect.tr_begin.tp_row = old_history_size;
+		rect.tr_end.tp_col = p->tp_col;
+		rect.tr_end.tp_row = p->tp_row;
+		vtbuf_fill(vb, &rect, VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR));
+
+		vb->vb_flags &= ~VBF_HISTORY_FULL;
 	} else {
-		/* Just update the size. */
-		vb->vb_scr_size = *p;
+		/*
+		 * Copy rows to the new buffer. The first row in the history
+		 * is back to index 0, ie. the new buffer doesn't cycle.
+		 *
+		 * (old_history_size - history_size) lines of history are
+		 * dropped.
+		 */
+		for (r = 0; r < history_size; r ++) {
+			row = rows[r];
+
+			/*
+			 * Compute the corresponding row in the old buffer.
+			 *
+			 * See the equivalent if{} block above for an
+			 * explanation.
+			 */
+			if (history_was_full)
+				oldrow = copyrows[
+				    (vb->vb_curroffset + h + r +
+				     (old_history_size - history_size)) %
+				    old_history_size];
+			else
+				oldrow = copyrows[
+				    (r + (old_history_size - history_size)) %
+				    old_history_size];
+
+			memmove(row, oldrow,
+			    MIN(p->tp_col, w) * sizeof(term_char_t));
+
+			/*
+			 * XXX VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR) will
+			 * extended lines of kernel text using the wrong
+			 * background color.
+			 */
+			for (c = MIN(p->tp_col, w); c < p->tp_col; c++) {
+				row[c] = VTBUF_SPACE_CHAR(TERMINAL_NORM_ATTR);
+			}
+		}
+
+		if (!history_was_full &&
+		    (vb->vb_curroffset + h) >= history_size)
+			vb->vb_flags |= VBF_HISTORY_FULL;
+	}
+
+	/*
+	 * If the screen is already filled (there are non-visible lines
+	 * above the current viewable area), adjust curroffset to the
+	 * new viewable area.
+	 */
+	if (!history_was_full && vb->vb_curroffset > 0) {
+		vb->vb_curroffset = vb->vb_curroffset + h - p->tp_row;
+		if (vb->vb_curroffset < 0)
+			vb->vb_curroffset += vb->vb_history_size;
+		vb->vb_curroffset %= vb->vb_history_size;
+		vb->vb_roffset = vb->vb_curroffset;
 	}
+
+	vtbuf_make_undirty(vb);
+	VTBUF_UNLOCK(vb);
+
+	/* Deallocate old buffer. */
+	free(old, M_VTBUF);
+	free(oldrows, M_VTBUF);
 }
 
 void

Modified: stable/10/sys/dev/vt/vt_core.c
==============================================================================
--- stable/10/sys/dev/vt/vt_core.c	Mon Sep 22 16:09:18 2014	(r271972)
+++ stable/10/sys/dev/vt/vt_core.c	Mon Sep 22 16:13:33 2014	(r271973)
@@ -484,18 +484,8 @@ vt_scroll(struct vt_window *vw, int offs
 	vt_termsize(vw->vw_device, vw->vw_font, &size);
 
 	diff = vthistory_seek(&vw->vw_buf, offset, whence);
-	/*
-	 * Offset changed, please update Nth lines on screen.
-	 * +N - Nth lines at top;
-	 * -N - Nth lines at bottom.
-	 */
-
-	if (diff < -size.tp_row || diff > size.tp_row) {
+	if (diff)
 		vw->vw_device->vd_flags |= VDF_INVALID;
-		vt_resume_flush_timer(vw->vw_device, 0);
-		return;
-	}
-	vw->vw_device->vd_flags |= VDF_INVALID; /*XXX*/
 	vt_resume_flush_timer(vw->vw_device, 0);
 }
 
@@ -796,7 +786,8 @@ vt_allocate_keyboard(struct vt_device *v
 				continue;
 
 			bzero(&ki, sizeof(ki));
-			strcpy(ki.kb_name, k->kb_name);
+			strncpy(ki.kb_name, k->kb_name, sizeof(ki.kb_name));
+			ki.kb_name[sizeof(ki.kb_name) - 1] = '\0';
 			ki.kb_unit = k->kb_unit;
 
 			kbdd_ioctl(k0, KBADDKBD, (caddr_t) &ki);
@@ -991,7 +982,6 @@ vt_flush(struct vt_device *vd)
 {
 	struct vt_window *vw;
 	struct vt_font *vf;
-	struct vt_bufmask tmask;
 	term_rect_t tarea;
 	term_pos_t size;
 #ifndef SC_NO_CUTPASTE
@@ -1047,14 +1037,13 @@ vt_flush(struct vt_device *vd)
 		vt_mark_mouse_position_as_dirty(vd);
 #endif
 
-	vtbuf_undirty(&vw->vw_buf, &tarea, &tmask);
+	vtbuf_undirty(&vw->vw_buf, &tarea);
 	vt_termsize(vd, vf, &size);
 
 	/* Force a full redraw when the screen contents are invalid. */
 	if (vd->vd_flags & VDF_INVALID) {
 		tarea.tr_begin.tp_row = tarea.tr_begin.tp_col = 0;
 		tarea.tr_end = size;
-		tmask.vbm_row = tmask.vbm_col = VBM_DIRTY;
 
 		vd->vd_flags &= ~VDF_INVALID;
 	}
@@ -1182,6 +1171,13 @@ vtterm_cnprobe(struct terminal *tm, stru
 		vt_compute_drawable_area(vw);
 	}
 
+	/*
+	 * The original screen size was faked (_VTDEFW x _VTDEFH). Now
+	 * that we have the real viewable size, fix it in the static
+	 * buffer.
+	 */
+	vt_termsize(vd, vw->vw_font, &vw->vw_buf.vb_scr_size);
+
 	vtbuf_init_early(&vw->vw_buf);
 	vt_winsize(vd, vw->vw_font, &wsz);
 	c = (boothowto & RB_MUTE) == 0 ? TERMINAL_KERN_ATTR :
@@ -2131,7 +2127,7 @@ skip_thunk:
 		win = *(int *)data - 1;
 		DPRINTF(5, "%s%d: VT_ACTIVATE ttyv%d ", SC_DRIVER_NAME,
 		    VT_UNIT(vw), win);
-		if ((win > VT_MAXWINDOWS) || (win < 0))
+		if ((win >= VT_MAXWINDOWS) || (win < 0))
 			return (EINVAL);
 		return (vt_proc_window_switch(vd->vd_windows[win]));
 	}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201409221613.s8MGDXWs076126>