summaryrefslogtreecommitdiffstats
path: root/sys/dev/vt
diff options
context:
space:
mode:
authordumbbell <dumbbell@FreeBSD.org>2014-09-22 16:13:33 +0000
committerdumbbell <dumbbell@FreeBSD.org>2014-09-22 16:13:33 +0000
commitc0941fa5beb7bdef60f13c2f91d783737a9d8918 (patch)
tree4e2380c5cec90a9182d5800c0c6899d75a886e57 /sys/dev/vt
parent1d7a8c573a30bab1fb55cd0ca8ce943c65e346ac (diff)
downloadFreeBSD-src-c0941fa5beb7bdef60f13c2f91d783737a9d8918.zip
FreeBSD-src-c0941fa5beb7bdef60f13c2f91d783737a9d8918.tar.gz
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)
Diffstat (limited to 'sys/dev/vt')
-rw-r--r--sys/dev/vt/vt.h8
-rw-r--r--sys/dev/vt/vt_buf.c282
-rw-r--r--sys/dev/vt/vt_core.c28
3 files changed, 179 insertions, 139 deletions
diff --git a/sys/dev/vt/vt.h b/sys/dev/vt/vt.h
index c804e56..2501928 100644
--- a/sys/dev/vt/vt.h
+++ b/sys/dev/vt/vt.h
@@ -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 *, const term_pos_t *, term_char_t);
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);
diff --git a/sys/dev/vt/vt_buf.c b/sys/dev/vt/vt_buf.c
index 28a7082..cc23b3b 100644
--- a/sys/dev/vt/vt_buf.c
+++ b/sys/dev/vt/vt_buf.c
@@ -76,44 +76,47 @@ vthistory_seek(struct vt_buf *vb, int offset, int whence)
}
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, int offset)
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, int row, int col)
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, const term_rect_t *area)
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, int size)
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_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));
- /* 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);
-
- /* 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
diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c
index 15151aa..4e8d19b 100644
--- a/sys/dev/vt/vt_core.c
+++ b/sys/dev/vt/vt_core.c
@@ -484,18 +484,8 @@ vt_scroll(struct vt_window *vw, int offset, int whence)
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 *vd)
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, struct consdev *cp)
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]));
}
OpenPOWER on IntegriCloud