feat(v4): the screen and the keyboards
The stick, increment 1, task 2 (plan 2026-10-26-stick-1-screen-and-keyboard;
docs/v4.0.0/STICK.md 2, 5.3, 5.4). On the v4 path:
- the framebuffer is brought up after POST, cleared and dark: console text
goes to serial only ("splash only, log on serial") until Zuse logs in;
then the screen is the console (TTF, a blinking cursor, as v3's), and
when she logs out it is cleared and dark again (console_fb_mirror(),
console_fb_clear(); the mirror is on by default, so v3 is unchanged);
- the line editor and the node's KEY read every keyboard -- PS/2, USB, the
virtio keyboard -- through the shared bridge (sk_input_getc()); the
headless wait drops keyboard input as well as serial bytes;
- an EMERGENCY_CONSOLE_ENABLED build has the screen from the start.
The framebuffer setup is one helper both paths call (kernel_main.c).
Red (before): screen_dark_until_login 153051 (10835 lit), console/keys
153309, logout 153609, kbd_typeahead 153918, virtio_kbd aarch64 154245
and riscv64 154718; no_framebuffer 155546 passed before and after.
Green: 155926 (0 lit), 160156, 160409 (0 lit after logout), 160630,
virtio_kbd 161414 and 161820, no_framebuffer 161206; usb_kbd with the USB
keyboard the only one (-machine i8042=off) 164548, v3 control 164757;
the identity gate's sessions 162245-163802 all pass; v3 typed by keyboard
164009, 164115. (usb_kbd 160857 and 164313 failed in the harness:
input-send-event's device names a display, not a keyboard.)
Accepted: suite EXIT 0; three clean qemu boots, POST 538/538, dict_hash
0xfec8c47cfc6f437f unchanged (174704, 174911, 175315); test-32, 39
modules, 0 failures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
0dbc98c049
commit
cab0ffb487
@@ -96,6 +96,15 @@ void console_fb_init(const FramebufferInfo *info, FbPixelFormat fmt);
|
||||
*/
|
||||
void console_fb_enable_ttf(void);
|
||||
|
||||
/* Whether console text is drawn on the framebuffer too (on by default, as
|
||||
* v3's console has it). The v4 boot turns it off until Zuse logs in, and
|
||||
* off again when she logs out: "splash only, log on serial"
|
||||
* (docs/v4.0.0/STICK.md 2). The serial line always has everything. */
|
||||
void console_fb_mirror(int on);
|
||||
|
||||
/* Erase the screen and put the cursor home (when the framebuffer is up). */
|
||||
void console_fb_clear(void);
|
||||
|
||||
/**
|
||||
* FABRIC-0.md item 4.4q: thin wrappers over vt100_scroll_back()/
|
||||
* vt100_scroll_fwd() -- see those functions' doc comments for the full
|
||||
|
||||
@@ -249,6 +249,21 @@ void console_describe_serial(void)
|
||||
static char g_active_vm_name_buf[CONSOLE_VM_NAME_BUF];
|
||||
static const char *g_active_vm_name = (void *)0;
|
||||
static int g_line_start = 1;
|
||||
|
||||
/* Whether console text is drawn on the framebuffer as well as sent to the
|
||||
* serial line. On unless a boot turns it off: v3's console mirrors from
|
||||
* console_fb_init() on, as always; the v4 boot keeps the screen dark until
|
||||
* Zuse logs in ("splash only, log on serial", docs/v4.0.0/STICK.md 2). */
|
||||
static int g_fb_mirror = 1;
|
||||
|
||||
static int fb_mirrored(void) { return g_fb_mirror && fb_is_available(); }
|
||||
|
||||
void console_fb_mirror(int on) { g_fb_mirror = on ? 1 : 0; }
|
||||
|
||||
void console_fb_clear(void)
|
||||
{
|
||||
if (fb_is_available()) vt100_puts("\x1b[2J\x1b[H");
|
||||
}
|
||||
static uint64_t g_console_tx_count; /* monotonic console_putc() counter (BSS) */
|
||||
|
||||
void console_set_vm_name(const char *name) {
|
||||
@@ -307,7 +322,7 @@ static void raw_putc(char c) {
|
||||
* function. */
|
||||
static void emit_prefix(void) {
|
||||
const char *p;
|
||||
int fb = fb_is_available();
|
||||
int fb = fb_mirrored();
|
||||
static const char *color_on = "\x1b[38;2;255;165;0m";
|
||||
static const char *color_off = "\x1b[39m";
|
||||
const char *user = g_user_prefix_fn ? g_user_prefix_fn() : (void *)0;
|
||||
@@ -383,8 +398,8 @@ static void console_putc_inner(char c)
|
||||
g_line_start = 1;
|
||||
}
|
||||
|
||||
/* --- framebuffer VT100 path (when available) --- */
|
||||
if (fb_is_available()) {
|
||||
/* --- framebuffer VT100 path (when available, and mirrored) --- */
|
||||
if (fb_mirrored()) {
|
||||
if (c == '\n') vt100_putc('\r');
|
||||
vt100_putc(c);
|
||||
}
|
||||
@@ -479,14 +494,14 @@ void console_fb_toggle_graphics(void)
|
||||
|
||||
void console_fb_draw_cursor(void)
|
||||
{
|
||||
if (fb_is_available()) {
|
||||
if (fb_mirrored()) {
|
||||
vt100_draw_cursor();
|
||||
}
|
||||
}
|
||||
|
||||
void console_fb_erase_cursor(void)
|
||||
{
|
||||
if (fb_is_available()) {
|
||||
if (fb_mirrored()) {
|
||||
vt100_erase_cursor();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,6 +465,21 @@ void kernel_main(BootInfo *boot_info) {
|
||||
}
|
||||
|
||||
#ifdef STARFORTH_ENABLE_VM
|
||||
/* The framebuffer the firmware handed over, as the console's screen, in
|
||||
* the pixel format GOP reported. Both systems' boots call it. */
|
||||
static void sk_console_fb_from_boot(const BootInfo *boot_info)
|
||||
{
|
||||
if (boot_info->framebuffer.base != NULL && boot_info->framebuffer.size > 0) {
|
||||
FbPixelFormat fb_fmt;
|
||||
switch (boot_info->framebuffer.pixel_format) {
|
||||
case (UINT32)PixelRedGreenBlueReserved8BitPerColor: fb_fmt = FB_PIXEL_RGBX32; break;
|
||||
case (UINT32)PixelBlueGreenRedReserved8BitPerColor: fb_fmt = FB_PIXEL_BGRX32; break;
|
||||
default: fb_fmt = FB_PIXEL_BGRX32; break;
|
||||
}
|
||||
console_fb_init(&boot_info->framebuffer, fb_fmt);
|
||||
}
|
||||
}
|
||||
|
||||
/* The logger after POST: whatever --log-level asked for (default: LOG_WARN).
|
||||
* Both systems' boots call it once POST is done. */
|
||||
static void sk_log_level_after_post(const BootInfo *boot_info)
|
||||
@@ -523,6 +538,15 @@ static void sk_v4_block_chain(void)
|
||||
} else {
|
||||
console_println("Artemis: virtio-blk found, and could not be attached");
|
||||
}
|
||||
|
||||
/* The screen and the keyboards, as the v3 path has them: the screen is
|
||||
* cleared and stays dark -- console text goes to serial only -- until
|
||||
* Zuse logs in (docs/v4.0.0/STICK.md 2 and 5.3; sk_v4_identity.c turns
|
||||
* it on). The virtio keyboard is the riscv64/aarch64 machines'; a
|
||||
* no-op where there is none. */
|
||||
console_fb_mirror(0);
|
||||
sk_console_fb_from_boot(sk_v4_boot_info);
|
||||
(void)virtio_input_find_keyboard();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -842,15 +866,7 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
||||
* see 4.5f) in exchange for the fuller on-screen record; Captain Bob's
|
||||
* call, made after 4.5f's -O2 experiment showed the earlier indefinite
|
||||
* -O0 stall was a compiler-optimization problem, not a correctness one. */
|
||||
if (boot_info->framebuffer.base != NULL && boot_info->framebuffer.size > 0) {
|
||||
FbPixelFormat fb_fmt;
|
||||
switch (boot_info->framebuffer.pixel_format) {
|
||||
case (UINT32)PixelRedGreenBlueReserved8BitPerColor: fb_fmt = FB_PIXEL_RGBX32; break;
|
||||
case (UINT32)PixelBlueGreenRedReserved8BitPerColor: fb_fmt = FB_PIXEL_BGRX32; break;
|
||||
default: fb_fmt = FB_PIXEL_BGRX32; break;
|
||||
}
|
||||
console_fb_init(&boot_info->framebuffer, fb_fmt);
|
||||
}
|
||||
sk_console_fb_from_boot(boot_info);
|
||||
|
||||
/* Copy capsule directory header to heap (has pointer field needing update) */
|
||||
CapsuleDirHeader *live_dir = (CapsuleDirHeader *)kmalloc(sizeof(CapsuleDirHeader));
|
||||
|
||||
+27
-4
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
#include "starkernel/v4/sk_v4.h"
|
||||
#include "starkernel/v4/sk_v4_identity.h"
|
||||
#include "starkernel/kbd_input.h"
|
||||
#include "starkernel/console.h"
|
||||
#include "starkernel/arch.h"
|
||||
#include "starkernel/timer.h"
|
||||
@@ -52,10 +53,11 @@ static void sk_v4_out(const char *text, unsigned len)
|
||||
for (i = 0; i < len; i++) console_putc(text[i]);
|
||||
}
|
||||
|
||||
/* a character for a line that reads the keyboard, when there is one */
|
||||
/* a character for a line that reads the keyboard, when there is one: the
|
||||
* serial line or any keyboard (docs/v4.0.0/STICK.md 5.4) */
|
||||
static int sk_v4_key(void)
|
||||
{
|
||||
int c = console_getc();
|
||||
int c = sk_input_getc();
|
||||
return c < 0 ? V4_BOOT_KEY_NONE : c;
|
||||
}
|
||||
|
||||
@@ -81,12 +83,25 @@ static void sk_v4_serve(v4_node *node, unsigned request)
|
||||
* (not in a build with EMERGENCY_CONSOLE_ENABLED, whose console needs no
|
||||
* login: v3's sk_console_readline() the same). While nothing is typed the
|
||||
* idle beat runs, as v3's. */
|
||||
#define SK_V4_CURSOR_BLINK 50u /* ticks between blinks, as v3's (500 ms at 100 Hz) */
|
||||
|
||||
static int sk_v4_readline(void)
|
||||
{
|
||||
int len = 0;
|
||||
int cursor_on = 1;
|
||||
uint64_t blink = heartbeat_ticks();
|
||||
|
||||
console_fb_draw_cursor();
|
||||
for (;;) {
|
||||
int c = console_getc();
|
||||
int c = sk_input_getc();
|
||||
if (c < 0) {
|
||||
uint64_t now = heartbeat_ticks();
|
||||
if (now - blink >= SK_V4_CURSOR_BLINK) {
|
||||
blink = now;
|
||||
cursor_on = !cursor_on;
|
||||
if (cursor_on) console_fb_draw_cursor();
|
||||
else console_fb_erase_cursor();
|
||||
}
|
||||
if (len == 0) {
|
||||
sk_v4_identity_beat();
|
||||
#if !EMERGENCY_CONSOLE_ENABLED
|
||||
@@ -98,13 +113,16 @@ static int sk_v4_readline(void)
|
||||
arch_relax();
|
||||
continue;
|
||||
}
|
||||
if (c == '\r' || c == '\n') { console_putc('\n'); return len; }
|
||||
if (c == '\r' || c == '\n') { console_fb_erase_cursor(); console_putc('\n'); return len; }
|
||||
if (c == 8 || c == 127) {
|
||||
if (len > 0) { len--; console_putc(8); console_putc(' '); console_putc(8); }
|
||||
} else if (c >= 32 && c < 127 && len < (int)SK_V4_LINE) {
|
||||
sk_v4_text[len++] = (char)c;
|
||||
console_putc((char)c);
|
||||
}
|
||||
cursor_on = 1; /* typing shows a solid cursor, as v3's */
|
||||
blink = heartbeat_ticks();
|
||||
console_fb_draw_cursor();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,6 +150,11 @@ void sk_v4_run(void (*chain)(void))
|
||||
}
|
||||
}
|
||||
sk_v4_identity_boot();
|
||||
#if EMERGENCY_CONSOLE_ENABLED
|
||||
/* a console that needs no login has the screen from the start */
|
||||
console_fb_mirror(1);
|
||||
console_fb_enable_ttf();
|
||||
#endif
|
||||
|
||||
/* The prompt is the host's: read a line, hand it to the node, say how it
|
||||
* ended. */
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "starkernel/blkio_usb.h"
|
||||
#include "starkernel/homeblocks_sig.h"
|
||||
#include "starkernel/capsule_zuse_boot.h"
|
||||
#include "starkernel/kbd_input.h"
|
||||
#ifdef ARCH_AMD64
|
||||
#include "starkernel/ioapic.h"
|
||||
#include "starkernel/i8042.h"
|
||||
@@ -117,6 +118,9 @@ static int sk_v4_drive_arrived(blkio_dev_t *dev)
|
||||
|
||||
console_set_vm_name("Hera");
|
||||
console_set_user_prefix_provider(sk_v4_user_prefix);
|
||||
/* the screen is the console from here (docs/v4.0.0/STICK.md 2) */
|
||||
console_fb_mirror(1);
|
||||
console_fb_enable_ttf();
|
||||
console_println("Zuse: identity confirmed from attached thumbdrive");
|
||||
if (!g_zuse_cert_installed) {
|
||||
memcpy(g_zuse_seed, seed, 32);
|
||||
@@ -136,6 +140,9 @@ static void sk_v4_drive_left(blkio_dev_t *dev)
|
||||
if (dev != g_zuse_dev) return;
|
||||
g_zuse_session = 0;
|
||||
g_zuse_dev = (struct blkio_dev *)0;
|
||||
/* nothing of her session is left on the screen; it is dark again */
|
||||
console_fb_clear();
|
||||
console_fb_mirror(0);
|
||||
console_println("Zuse: session ended -- reattach to re-authenticate");
|
||||
}
|
||||
|
||||
@@ -197,12 +204,13 @@ void sk_v4_identity_check_now(void)
|
||||
sk_v4_idle();
|
||||
}
|
||||
|
||||
/* What was typed at a headless machine is no one's: it is read and dropped,
|
||||
* so that it does not run as whoever logs in next (the identity gate's
|
||||
* final review, item 4, 2026-10-26). */
|
||||
/* What was typed at a headless machine -- on the serial line or any
|
||||
* keyboard -- is no one's: it is read and dropped, so that it does not run
|
||||
* as whoever logs in next (the identity gate's final review, item 4,
|
||||
* 2026-10-26). */
|
||||
static void sk_v4_discard_input(void)
|
||||
{
|
||||
while (console_getc() >= 0) { }
|
||||
sk_input_drop();
|
||||
}
|
||||
|
||||
void sk_v4_identity_wait(void)
|
||||
|
||||
Reference in New Issue
Block a user