Twelve login terminals, root only, console fixes, a faster build, a Niveus splash, and X back on evdev

- tty1-tty12 all run login; the image has only root. /dev/tty7..12 could not
  be written (cdev.c knew minors 10-16 only), which sent their jobs into a
  restart storm that took the supervisor down; fixed, and stat reports them as
  Linux's tty7..12.
- Erasing text at a prompt did nothing: erase_one sent a bare backspace, which
  only moves; it and the echo path now send back-blank-back through vt_feed.
- A white cursor block was left at the end of every line of a verbose boot:
  a line feed at the bottom scrolls the pixels, cursor included, and the
  cursor was erased after the scroll. It comes off first now. A blank cell is
  also marked dirty, which it was not.
- ldlsd died with a general protection fault on real hardware in its variadic
  log function: Linux module code calls with an 8-byte-aligned stack and an
  unset %al, and the prologue's movaps faults. LDLS guest code is built with
  -mstackrealign.
- make iso took over a minute for any change, because staging r8169 rewrote
  the same files and every mtime moved; it now replaces files only if their
  contents differ (about 10 s).
- The loader's splash is redrawn in the boot manager's style, and the boot
  manager shows its cursor whenever a pointer device exists.
- xf86-input-libinput is out of the image again: with it Xorg took both
  keyboard and pointer from libinput and, on the user's laptop, neither worked.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EVRhxi9zpdW2uDUN4FVcao
This commit is contained in:
Nexoniarz 2026-10-26 17:43:44 +01:00
commit 2aef583aad
23 changed files with 290 additions and 155 deletions

View file

@ -302,7 +302,7 @@ consputc(int c)
uartputc('\b'); uartputc(' '); uartputc('\b');
if (!cons_serial_only) {
struct vt *v = vt_current();
vt_putc(v, '\b'); vt_putc(v, ' '); vt_putc(v, '\b');
vt_feed(v, '\b'); vt_feed(v, ' '); vt_feed(v, '\b');
}
return;
}
@ -452,8 +452,12 @@ erase_one(struct vt *v)
v->in.e--;
if (v->tio.c_lflag & ECHOE) {
if (v == vt_current()) { uartputc('\b'); uartputc(' '); uartputc('\b'); }
if (!cons_serial_only)
vt_putc(v, '\b');
// Back, blank, back -- and through vt_feed, which keeps the text cursor
// in step. A bare \b only moves (see vt.c), so this used to leave the
// rubbed-out character on screen and the cursor block behind it.
if (!cons_serial_only) {
vt_feed(v, '\b'); vt_feed(v, ' '); vt_feed(v, '\b');
}
}
}

View file

@ -149,9 +149,10 @@ memread(struct inode *ip, uint64 off, char *dst, int n)
case 1: return consoleread(ip, off, dst, n);
case 2: return nullread(ip, off, dst, n);
case 3: return consoleread(ip, off, dst, n);
/* 10 = /dev/tty, 11..16 = /dev/tty1..tty6. consoleread resolves the
/* 10 = /dev/tty, 11..22 = /dev/tty1..tty12. consoleread resolves the
minor to a terminal; see vt_for_minor(). */
case 10: case 11: case 12: case 13: case 14: case 15: case 16:
case 17: case 18: case 19: case 20: case 21: case 22:
return consoleread(ip, off, dst, n);
case 5: return zeroread(ip, off, dst, n);
case 7: return zeroread(ip, off, dst, n); // /dev/full reads as zeros
@ -169,6 +170,7 @@ memwrite(struct inode *ip, uint64 off, char *dst, int n)
switch(ip->minor) {
case 1: return consolewrite(ip, off, dst, n);
case 10: case 11: case 12: case 13: case 14: case 15: case 16:
case 17: case 18: case 19: case 20: case 21: case 22:
return consolewrite(ip, off, dst, n);
case 7: return fullwrite(ip, off, dst, n); // /dev/full: always ENOSPC
case 3: // /dev/keyboard: discarded

View file

@ -406,6 +406,11 @@ draw_glyph_px(int x, int y, uint32 cp, uint32 fg, uint32 bg)
for (int c = 0; c < cell_w; c++)
gfx_draw_pixel(x + c, y + r, bg);
// Dirty before the early return: a blank cell is a background fill and
// nothing else, and that fill is what rubs the text cursor out. Marked
// only after the glyph, the blank was drawn to the back buffer and never
// copied to the screen -- a block left at the end of every line.
dirty(x, y, x + cell_w - 1, y + cell_h - 1);
if (cp == ' ')
return; // nothing to draw over the background

View file

@ -1241,20 +1241,26 @@ vt_cycle(int dir)
void
vt_feed(struct vt *v, int c)
{
// The grid is the truth, so the old cursor cell can be repainted from it
// *after* the byte is consumed -- which lets two cases cost nothing:
// - a byte inside an escape sequence changes nothing on screen;
// - a plain glyph is drawn over the cell the cursor sat on, which repaints
// it anyway (unless a wrap is pending, when it lands on the next line).
// A plain glyph is drawn over the cell the cursor sits on, which repaints it
// anyway (unless a wrap is pending, when it lands on the next line), so the
// cursor needs no separate erase there.
int mid = v->esc_state != VE_NORMAL;
int over = !mid && !v->wrap_pending && c >= 0x20 && c < 0x7f &&
v->u8_need == 0;
vt_feed_1(v, c);
if (mid && v->esc_state != VE_NORMAL)
return;
if (over)
if (over) {
vt_feed_1(v, c);
v->curs_drawn = 0;
else
cursor_erase(v);
cursor_draw(v);
return;
}
// Anything else may move the cursor, and a line feed at the bottom scrolls
// the *pixels*, block and all. So the cursor comes off first. Erased after
// the scroll, it was repainted where the cell had been and the old block
// went up a row with the text: a white block at the end of every line of a
// verbose boot.
cursor_erase(v);
vt_feed_1(v, c);
cursor_draw(v);
}

View file

@ -82,7 +82,7 @@ static uint64
linux_tty_rdev(uint32 major, uint32 minor)
{
if (major == 1 && minor == 0) return linux_makedev(4, 0);
if (major == 1 && minor >= 11 && minor <= 16) return linux_makedev(4, minor - 10);
if (major == 1 && minor >= 11 && minor <= 22) return linux_makedev(4, minor - 10);
if (major == 1 && minor == 10) return linux_makedev(5, 0);
if (major == 1 && minor == 1) return linux_makedev(5, 1);
// Pseudo-terminals, as Linux numbers them: ptmx (5, 2), slaves 136.