refactor(kernel): the keyboard bridge, shared
The stick, increment 1, task 1 (plan 2026-10-26-stick-1-screen-and-keyboard). repl.c's keyboard bridge -- the key tables, Shift/Alt/Caps Lock/Num Lock and their lights, the keypad, Alt+TAB, and the per-tick USB keyboard servicing -- moves unchanged to kernel/src/hal/kbd_input.c as sk_input_getc() (and sk_input_drop()), so that the v4 boot's console reads the same keyboards (docs/v4.0.0/STICK.md 5.4). v3's behaviour is unchanged. scripts/qemu_session.py: the typed-QEMU-session harness, kept in the repo from here on (the identity gate's sessions, and v3_keys: system=v3 typed on QEMU's keyboard with send-key). Yardstick, system=v3 typed by keyboard: before, amd64 PS/2 134805 PASS, aarch64 virtio keyboard 135549 PASS; after, 135746 and 135835 PASS. (riscv64 134850: v3 never reached its prompt -- Artemis virtio_blk writes time out; v3's block path, before this change; being investigated.) Accepted: suite EXIT 0; three clean qemu boots to [zuse@Hera] ok>, POST 538/538, dict_hash 0xfec8c47cfc6f437f (145722, 145859, 150231); 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
6f96502fdf
commit
83d3692976
@@ -0,0 +1,18 @@
|
||||
/* kbd_input.h -- one byte of console input, from the serial line or a
|
||||
* keyboard (PS/2, USB boot keyboard, virtio keyboard). Both systems'
|
||||
* consoles read through it: v3's (kernel/src/repl.c) and the v4 boot's
|
||||
* (kernel/src/v4/sk_v4.c). docs/v4.0.0/STICK.md 5.4.
|
||||
*/
|
||||
#ifndef STARKERNEL_KBD_INPUT_H
|
||||
#define STARKERNEL_KBD_INPUT_H
|
||||
|
||||
/* One raw byte from the serial line or a keyboard, non-blocking; -1 when
|
||||
* neither has one. While a USB keyboard runs, its xHCI event ring is serviced
|
||||
* once per timer tick here. Alt+TAB toggles the framebuffer's graphics/text
|
||||
* view and types nothing. */
|
||||
int sk_input_getc(void);
|
||||
|
||||
/* Read and drop every byte and key that is waiting. */
|
||||
void sk_input_drop(void);
|
||||
|
||||
#endif /* STARKERNEL_KBD_INPUT_H */
|
||||
@@ -0,0 +1,193 @@
|
||||
/* kbd_input.c -- one byte of console input, from the serial line or a
|
||||
* keyboard: the keyboard bridge, moved here from kernel/src/repl.c on
|
||||
* 2026-10-26 unchanged in behaviour, so that v3's console and the v4 boot's
|
||||
* read the same keyboards (docs/v4.0.0/STICK.md 5.4;
|
||||
* docs/v4.0.0/plans/2026-10-26-stick-1-screen-and-keyboard.md, task 1).
|
||||
*/
|
||||
#include "starkernel/kbd_input.h"
|
||||
#include "console.h"
|
||||
#include "starkernel/timer.h"
|
||||
#include "starkernel/xhci_driver.h"
|
||||
#include "starkernel/usb_kbd.h" /* usb_kbd_set_leds() -- the lock lights, A3 */
|
||||
#include "word_source/include/keyboard_words.h" /* sk_key_event_poll() */
|
||||
#include <stdint.h>
|
||||
|
||||
/*===========================================================================
|
||||
* FABRIC-0.md item 4.4v: keyboard-to-REPL bridge.
|
||||
*
|
||||
* Translates sk_key_event_poll()'s converged Linux-keycode-namespace
|
||||
* stream (keyboard_words.c -- one implementation shared with KEY-EVENT,
|
||||
* live-verified on all three architectures per item 4.3.5f) into the same
|
||||
* byte stream sk_console_readline() already reads from console_getc(): -1 for
|
||||
* "nothing ready", else a raw ASCII byte with '\n'/0x7F meaning the same
|
||||
* thing they mean for the serial path below.
|
||||
*
|
||||
* Table covers exactly the keys a line editor needs -- letters, digits,
|
||||
* the standard US-QWERTY punctuation row, space, enter, backspace, tab
|
||||
* (for the Ctrl+TAB toggle interception, 4.4y/4.4u step 8) -- not full
|
||||
* keyboard coverage. Keycodes are Linux input-event-codes.h values,
|
||||
* confirmed against this build host's own header, not guessed (§25.0
|
||||
* rule 4). Index 0 means "no mapping"; arrows/F-keys/etc. fall through
|
||||
* unmapped and are silently dropped, consistent with this REPL's
|
||||
* append/backspace-only editing model (4.4u: no mid-line cursor
|
||||
* movement).
|
||||
*===========================================================================*/
|
||||
|
||||
#define SK_KBD_TABLE_SIZE 98u /* highest keycode used below is KEY_RIGHTCTRL=97 */
|
||||
|
||||
static const char sk_kbd_unshifted[SK_KBD_TABLE_SIZE] = {
|
||||
[2]='1',[3]='2',[4]='3',[5]='4',[6]='5',[7]='6',[8]='7',[9]='8',[10]='9',[11]='0',
|
||||
[12]='-',[13]='=',
|
||||
[16]='q',[17]='w',[18]='e',[19]='r',[20]='t',[21]='y',[22]='u',[23]='i',[24]='o',[25]='p',
|
||||
[26]='[',[27]=']',
|
||||
[30]='a',[31]='s',[32]='d',[33]='f',[34]='g',[35]='h',[36]='j',[37]='k',[38]='l',
|
||||
[39]=';',[40]='\'',[41]='`',[43]='\\',
|
||||
[44]='z',[45]='x',[46]='c',[47]='v',[48]='b',[49]='n',[50]='m',
|
||||
[51]=',',[52]='.',[53]='/',
|
||||
[57]=' ',
|
||||
};
|
||||
|
||||
static const char sk_kbd_shifted[SK_KBD_TABLE_SIZE] = {
|
||||
[2]='!',[3]='@',[4]='#',[5]='$',[6]='%',[7]='^',[8]='&',[9]='*',[10]='(',[11]=')',
|
||||
[12]='_',[13]='+',
|
||||
[16]='Q',[17]='W',[18]='E',[19]='R',[20]='T',[21]='Y',[22]='U',[23]='I',[24]='O',[25]='P',
|
||||
[26]='{',[27]='}',
|
||||
[30]='A',[31]='S',[32]='D',[33]='F',[34]='G',[35]='H',[36]='J',[37]='K',[38]='L',
|
||||
[39]=':',[40]='"',[41]='~',[43]='|',
|
||||
[44]='Z',[45]='X',[46]='C',[47]='V',[48]='B',[49]='N',[50]='M',
|
||||
[51]='<',[52]='>',[53]='?',
|
||||
[57]=' ',
|
||||
};
|
||||
|
||||
#define SK_KEY_BACKSPACE 14u
|
||||
#define SK_KEY_TAB 15u
|
||||
#define SK_KEY_ENTER 28u
|
||||
#define SK_KEY_LEFTSHIFT 42u
|
||||
#define SK_KEY_RIGHTSHIFT 54u
|
||||
#define SK_KEY_LEFTALT 56u
|
||||
#define SK_KEY_RIGHTALT 100u
|
||||
#define SK_KEY_CAPSLOCK 58u
|
||||
#define SK_KEY_NUMLOCK 69u
|
||||
#define SK_KEY_KPENTER 96u
|
||||
#define SK_KEY_KPSLASH 98u
|
||||
#define SK_KEY_102ND 86u
|
||||
|
||||
static int g_kbd_shift_down; /* zero-initialized (BSS) */
|
||||
static int g_kbd_alt_down;
|
||||
|
||||
/* A full-size keyboard (Captain Bob, 2026-10-14: "include caps lock,
|
||||
* numlock, keypad and arrow"). Caps Lock and Num Lock are toggles, held
|
||||
* here for every keyboard alike and shown on a USB keyboard's lights
|
||||
* (usb_kbd_set_leds()). Num Lock starts on, as a PC's firmware usually
|
||||
* leaves it. Caps Lock acts on letters only; Shift reverses it. */
|
||||
static int g_kbd_caps_lock;
|
||||
static int g_kbd_num_lock = 1;
|
||||
|
||||
static void sk_kbd_show_locks(void)
|
||||
{
|
||||
usb_kbd_set_leds((uint8_t)((g_kbd_num_lock ? USB_KBD_LED_NUM : 0) |
|
||||
(g_kbd_caps_lock ? USB_KBD_LED_CAPS : 0)));
|
||||
}
|
||||
|
||||
/* The keypad: what each key types. With Num Lock on, 0-9 and '.'; with it
|
||||
* off those are Home/arrows/PgUp/... -- navigation, which this REPL's
|
||||
* append/backspace editing has no use for, so they type nothing (as the
|
||||
* arrow keys do). / * - + always type; keypad Enter is Enter. */
|
||||
static int sk_kbd_keypad(uint16_t keycode)
|
||||
{
|
||||
switch (keycode) {
|
||||
case 55u: return '*';
|
||||
case 74u: return '-';
|
||||
case 78u: return '+';
|
||||
case SK_KEY_KPSLASH: return '/';
|
||||
case SK_KEY_KPENTER: return '\n';
|
||||
default: break;
|
||||
}
|
||||
if (!g_kbd_num_lock) return 0;
|
||||
switch (keycode) {
|
||||
case 71u: return '7'; case 72u: return '8'; case 73u: return '9';
|
||||
case 75u: return '4'; case 76u: return '5'; case 77u: return '6';
|
||||
case 79u: return '1'; case 80u: return '2'; case 81u: return '3';
|
||||
case 82u: return '0'; case 83u: return '.';
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Drains and translates one physically-typed key. Modifier state persists
|
||||
* across calls (a real keyboard's shift/alt state is global, not
|
||||
* per-line). Alt+TAB is intercepted here and drives the graphics/text
|
||||
* toggle directly (console_fb_toggle_graphics(), the same state-machine
|
||||
* transition the ALT+TAB FORTH word calls) -- never reaches the line
|
||||
* buffer as a character either way. */
|
||||
static int sk_kbd_getc(void)
|
||||
{
|
||||
uint16_t keycode;
|
||||
int pressed;
|
||||
|
||||
while (sk_key_event_poll(&keycode, &pressed)) {
|
||||
if (keycode == SK_KEY_LEFTSHIFT || keycode == SK_KEY_RIGHTSHIFT) {
|
||||
g_kbd_shift_down = pressed;
|
||||
continue;
|
||||
}
|
||||
if (keycode == SK_KEY_LEFTALT || keycode == SK_KEY_RIGHTALT) {
|
||||
g_kbd_alt_down = pressed;
|
||||
continue;
|
||||
}
|
||||
if (!pressed) continue; /* only act on press/repeat */
|
||||
|
||||
if (keycode == SK_KEY_CAPSLOCK) { g_kbd_caps_lock = !g_kbd_caps_lock; sk_kbd_show_locks(); continue; }
|
||||
if (keycode == SK_KEY_NUMLOCK) { g_kbd_num_lock = !g_kbd_num_lock; sk_kbd_show_locks(); continue; }
|
||||
{
|
||||
int k = sk_kbd_keypad(keycode);
|
||||
if (k) return k;
|
||||
}
|
||||
if (keycode == SK_KEY_102ND) return g_kbd_shift_down ? '|' : '\\';
|
||||
|
||||
if (keycode == SK_KEY_TAB) {
|
||||
if (g_kbd_alt_down) console_fb_toggle_graphics();
|
||||
continue; /* bare TAB: not mapped, same as arrows/F-keys */
|
||||
}
|
||||
if (keycode == SK_KEY_ENTER) return '\n';
|
||||
if (keycode == SK_KEY_BACKSPACE) return 0x7F;
|
||||
|
||||
if (keycode < SK_KBD_TABLE_SIZE) {
|
||||
char lower = sk_kbd_unshifted[keycode];
|
||||
int shift = g_kbd_shift_down;
|
||||
if (lower >= 'a' && lower <= 'z' && g_kbd_caps_lock) shift = !shift;
|
||||
char c = shift ? sk_kbd_shifted[keycode] : lower;
|
||||
if (c) return (unsigned char)c;
|
||||
}
|
||||
/* unmapped keycode -- drop and keep draining */
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* One raw byte from either input source (serial console or the keyboard-
|
||||
* event bridge), non-blocking, -1 if neither has one ready right now. Not
|
||||
* itself a FORTH word -- the shared byte-fetch underneath sk_console_getkey()/
|
||||
* sk_console_key_available() (the standard dictionary's KEY/?TERMINAL, wired
|
||||
* through shim.c's getchar()) and sk_console_readline() (QUERY/EXPECT, wired
|
||||
* through shim.c's fgets()) alike. */
|
||||
static uint64_t g_kbd_poll_tick;
|
||||
|
||||
int sk_input_getc(void)
|
||||
{
|
||||
/* A USB keyboard's reports come in on the xHCI event ring: while one is
|
||||
* running, service the ring once per timer tick here, not only on the
|
||||
* once-a-second idle beat -- keys arrive at typing speed (A3). */
|
||||
if (xhci_keyboard_running()) {
|
||||
uint64_t t = heartbeat_ticks();
|
||||
if (t != g_kbd_poll_tick) {
|
||||
g_kbd_poll_tick = t;
|
||||
xhci_poll_events();
|
||||
}
|
||||
}
|
||||
int c = console_getc();
|
||||
if (c < 0) c = sk_kbd_getc(); /* FABRIC-0.md 4.4v: second source, same buffer */
|
||||
return c;
|
||||
}
|
||||
|
||||
void sk_input_drop(void)
|
||||
{
|
||||
while (sk_input_getc() >= 0) { }
|
||||
}
|
||||
+9
-179
@@ -50,7 +50,7 @@
|
||||
#include "starkernel/vm/stadium.h" /* task 3.8 -- stadium_conserved() evidence print */
|
||||
#include "block_subsystem.h"
|
||||
#include "word_source/include/keyboard_words.h"
|
||||
#include "starkernel/usb_kbd.h" /* usb_kbd_set_leds() -- the lock lights, A3 */
|
||||
#include "starkernel/kbd_input.h" /* sk_input_getc() */
|
||||
#include "word_source/include/block_words.h"
|
||||
#include "word_registry.h"
|
||||
#include "freestanding/stdio.h"
|
||||
@@ -869,180 +869,10 @@ static void sk_repl_idle(VM *active_vm)
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================
|
||||
* FABRIC-0.md item 4.4v: keyboard-to-REPL bridge.
|
||||
*
|
||||
* Translates sk_key_event_poll()'s converged Linux-keycode-namespace
|
||||
* stream (keyboard_words.c -- one implementation shared with KEY-EVENT,
|
||||
* live-verified on all three architectures per item 4.3.5f) into the same
|
||||
* byte stream sk_console_readline() already reads from console_getc(): -1 for
|
||||
* "nothing ready", else a raw ASCII byte with '\n'/0x7F meaning the same
|
||||
* thing they mean for the serial path below.
|
||||
*
|
||||
* Table covers exactly the keys a line editor needs -- letters, digits,
|
||||
* the standard US-QWERTY punctuation row, space, enter, backspace, tab
|
||||
* (for the Ctrl+TAB toggle interception, 4.4y/4.4u step 8) -- not full
|
||||
* keyboard coverage. Keycodes are Linux input-event-codes.h values,
|
||||
* confirmed against this build host's own header, not guessed (§25.0
|
||||
* rule 4). Index 0 means "no mapping"; arrows/F-keys/etc. fall through
|
||||
* unmapped and are silently dropped, consistent with this REPL's
|
||||
* append/backspace-only editing model (4.4u: no mid-line cursor
|
||||
* movement).
|
||||
*===========================================================================*/
|
||||
|
||||
#define SK_KBD_TABLE_SIZE 98u /* highest keycode used below is KEY_RIGHTCTRL=97 */
|
||||
|
||||
static const char sk_kbd_unshifted[SK_KBD_TABLE_SIZE] = {
|
||||
[2]='1',[3]='2',[4]='3',[5]='4',[6]='5',[7]='6',[8]='7',[9]='8',[10]='9',[11]='0',
|
||||
[12]='-',[13]='=',
|
||||
[16]='q',[17]='w',[18]='e',[19]='r',[20]='t',[21]='y',[22]='u',[23]='i',[24]='o',[25]='p',
|
||||
[26]='[',[27]=']',
|
||||
[30]='a',[31]='s',[32]='d',[33]='f',[34]='g',[35]='h',[36]='j',[37]='k',[38]='l',
|
||||
[39]=';',[40]='\'',[41]='`',[43]='\\',
|
||||
[44]='z',[45]='x',[46]='c',[47]='v',[48]='b',[49]='n',[50]='m',
|
||||
[51]=',',[52]='.',[53]='/',
|
||||
[57]=' ',
|
||||
};
|
||||
|
||||
static const char sk_kbd_shifted[SK_KBD_TABLE_SIZE] = {
|
||||
[2]='!',[3]='@',[4]='#',[5]='$',[6]='%',[7]='^',[8]='&',[9]='*',[10]='(',[11]=')',
|
||||
[12]='_',[13]='+',
|
||||
[16]='Q',[17]='W',[18]='E',[19]='R',[20]='T',[21]='Y',[22]='U',[23]='I',[24]='O',[25]='P',
|
||||
[26]='{',[27]='}',
|
||||
[30]='A',[31]='S',[32]='D',[33]='F',[34]='G',[35]='H',[36]='J',[37]='K',[38]='L',
|
||||
[39]=':',[40]='"',[41]='~',[43]='|',
|
||||
[44]='Z',[45]='X',[46]='C',[47]='V',[48]='B',[49]='N',[50]='M',
|
||||
[51]='<',[52]='>',[53]='?',
|
||||
[57]=' ',
|
||||
};
|
||||
|
||||
#define SK_KEY_BACKSPACE 14u
|
||||
#define SK_KEY_TAB 15u
|
||||
#define SK_KEY_ENTER 28u
|
||||
#define SK_KEY_LEFTSHIFT 42u
|
||||
#define SK_KEY_RIGHTSHIFT 54u
|
||||
#define SK_KEY_LEFTALT 56u
|
||||
#define SK_KEY_RIGHTALT 100u
|
||||
#define SK_KEY_CAPSLOCK 58u
|
||||
#define SK_KEY_NUMLOCK 69u
|
||||
#define SK_KEY_KPENTER 96u
|
||||
#define SK_KEY_KPSLASH 98u
|
||||
#define SK_KEY_102ND 86u
|
||||
|
||||
static int g_kbd_shift_down; /* zero-initialized (BSS) */
|
||||
static int g_kbd_alt_down;
|
||||
|
||||
/* A full-size keyboard (Captain Bob, 2026-10-14: "include caps lock,
|
||||
* numlock, keypad and arrow"). Caps Lock and Num Lock are toggles, held
|
||||
* here for every keyboard alike and shown on a USB keyboard's lights
|
||||
* (usb_kbd_set_leds()). Num Lock starts on, as a PC's firmware usually
|
||||
* leaves it. Caps Lock acts on letters only; Shift reverses it. */
|
||||
static int g_kbd_caps_lock;
|
||||
static int g_kbd_num_lock = 1;
|
||||
|
||||
static void sk_kbd_show_locks(void)
|
||||
{
|
||||
usb_kbd_set_leds((uint8_t)((g_kbd_num_lock ? USB_KBD_LED_NUM : 0) |
|
||||
(g_kbd_caps_lock ? USB_KBD_LED_CAPS : 0)));
|
||||
}
|
||||
|
||||
/* The keypad: what each key types. With Num Lock on, 0-9 and '.'; with it
|
||||
* off those are Home/arrows/PgUp/... -- navigation, which this REPL's
|
||||
* append/backspace editing has no use for, so they type nothing (as the
|
||||
* arrow keys do). / * - + always type; keypad Enter is Enter. */
|
||||
static int sk_kbd_keypad(uint16_t keycode)
|
||||
{
|
||||
switch (keycode) {
|
||||
case 55u: return '*';
|
||||
case 74u: return '-';
|
||||
case 78u: return '+';
|
||||
case SK_KEY_KPSLASH: return '/';
|
||||
case SK_KEY_KPENTER: return '\n';
|
||||
default: break;
|
||||
}
|
||||
if (!g_kbd_num_lock) return 0;
|
||||
switch (keycode) {
|
||||
case 71u: return '7'; case 72u: return '8'; case 73u: return '9';
|
||||
case 75u: return '4'; case 76u: return '5'; case 77u: return '6';
|
||||
case 79u: return '1'; case 80u: return '2'; case 81u: return '3';
|
||||
case 82u: return '0'; case 83u: return '.';
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Drains and translates one physically-typed key. Modifier state persists
|
||||
* across calls (a real keyboard's shift/alt state is global, not
|
||||
* per-line). Alt+TAB is intercepted here and drives the graphics/text
|
||||
* toggle directly (console_fb_toggle_graphics(), the same state-machine
|
||||
* transition the ALT+TAB FORTH word calls) -- never reaches the line
|
||||
* buffer as a character either way. */
|
||||
static int sk_kbd_getc(void)
|
||||
{
|
||||
uint16_t keycode;
|
||||
int pressed;
|
||||
|
||||
while (sk_key_event_poll(&keycode, &pressed)) {
|
||||
if (keycode == SK_KEY_LEFTSHIFT || keycode == SK_KEY_RIGHTSHIFT) {
|
||||
g_kbd_shift_down = pressed;
|
||||
continue;
|
||||
}
|
||||
if (keycode == SK_KEY_LEFTALT || keycode == SK_KEY_RIGHTALT) {
|
||||
g_kbd_alt_down = pressed;
|
||||
continue;
|
||||
}
|
||||
if (!pressed) continue; /* only act on press/repeat */
|
||||
|
||||
if (keycode == SK_KEY_CAPSLOCK) { g_kbd_caps_lock = !g_kbd_caps_lock; sk_kbd_show_locks(); continue; }
|
||||
if (keycode == SK_KEY_NUMLOCK) { g_kbd_num_lock = !g_kbd_num_lock; sk_kbd_show_locks(); continue; }
|
||||
{
|
||||
int k = sk_kbd_keypad(keycode);
|
||||
if (k) return k;
|
||||
}
|
||||
if (keycode == SK_KEY_102ND) return g_kbd_shift_down ? '|' : '\\';
|
||||
|
||||
if (keycode == SK_KEY_TAB) {
|
||||
if (g_kbd_alt_down) console_fb_toggle_graphics();
|
||||
continue; /* bare TAB: not mapped, same as arrows/F-keys */
|
||||
}
|
||||
if (keycode == SK_KEY_ENTER) return '\n';
|
||||
if (keycode == SK_KEY_BACKSPACE) return 0x7F;
|
||||
|
||||
if (keycode < SK_KBD_TABLE_SIZE) {
|
||||
char lower = sk_kbd_unshifted[keycode];
|
||||
int shift = g_kbd_shift_down;
|
||||
if (lower >= 'a' && lower <= 'z' && g_kbd_caps_lock) shift = !shift;
|
||||
char c = shift ? sk_kbd_shifted[keycode] : lower;
|
||||
if (c) return (unsigned char)c;
|
||||
}
|
||||
/* unmapped keycode -- drop and keep draining */
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* One raw byte from either input source (serial console or the keyboard-
|
||||
* event bridge), non-blocking, -1 if neither has one ready right now. Not
|
||||
* itself a FORTH word -- the shared byte-fetch underneath sk_console_getkey()/
|
||||
* sk_console_key_available() (the standard dictionary's KEY/?TERMINAL, wired
|
||||
* through shim.c's getchar()) and sk_console_readline() (QUERY/EXPECT, wired
|
||||
* through shim.c's fgets()) alike. */
|
||||
static uint64_t g_kbd_poll_tick;
|
||||
|
||||
static int sk_console_getc_raw(void)
|
||||
{
|
||||
/* A USB keyboard's reports come in on the xHCI event ring: while one is
|
||||
* running, service the ring once per timer tick here, not only on the
|
||||
* once-a-second idle beat -- keys arrive at typing speed (A3). */
|
||||
if (xhci_keyboard_running()) {
|
||||
uint64_t t = heartbeat_ticks();
|
||||
if (t != g_kbd_poll_tick) {
|
||||
g_kbd_poll_tick = t;
|
||||
xhci_poll_events();
|
||||
}
|
||||
}
|
||||
int c = console_getc();
|
||||
if (c < 0) c = sk_kbd_getc(); /* FABRIC-0.md 4.4v: second source, same buffer */
|
||||
return c;
|
||||
}
|
||||
/* The keyboard bridge -- the key tables, Shift/Alt/Caps Lock/Num Lock, the
|
||||
* keypad, Alt+TAB and the per-tick USB keyboard servicing -- is the HAL's
|
||||
* since 2026-10-26 (kernel/src/hal/kbd_input.c, sk_input_getc()), so that
|
||||
* the v4 boot's console reads the same keyboards (docs/v4.0.0/STICK.md 5.4). */
|
||||
|
||||
/* One-byte pushback so sk_console_key_available() can peek without losing
|
||||
* the byte -- ?TERMINAL must be non-destructive (a caller checks readiness,
|
||||
@@ -1067,7 +897,7 @@ int sk_console_getkey(VM *active_vm)
|
||||
c = g_console_pending_key;
|
||||
g_console_pending_key = -1;
|
||||
} else {
|
||||
c = sk_console_getc_raw();
|
||||
c = sk_input_getc();
|
||||
}
|
||||
if (c >= 0) return c;
|
||||
|
||||
@@ -1118,7 +948,7 @@ void sk_repl_headless_wait(VM *mama)
|
||||
int sk_console_key_available(void)
|
||||
{
|
||||
if (g_console_pending_key >= 0) return 1;
|
||||
int c = sk_console_getc_raw();
|
||||
int c = sk_input_getc();
|
||||
if (c >= 0) { g_console_pending_key = c; return 1; }
|
||||
return 0;
|
||||
}
|
||||
@@ -1177,7 +1007,7 @@ int sk_console_readline(char* buf, int size, VM* active_vm, int reanchor_prompt)
|
||||
c = g_console_pending_key;
|
||||
g_console_pending_key = -1;
|
||||
} else {
|
||||
c = sk_console_getc_raw();
|
||||
c = sk_input_getc();
|
||||
}
|
||||
|
||||
if (c < 0) {
|
||||
@@ -1336,7 +1166,7 @@ int sk_console_readline(char* buf, int size, VM* active_vm, int reanchor_prompt)
|
||||
* matches every other non-blocking read in this function. */
|
||||
{
|
||||
int pair = (c == '\r') ? '\n' : '\r';
|
||||
int next = sk_console_getc_raw();
|
||||
int next = sk_input_getc();
|
||||
if (next >= 0 && next != pair) g_console_pending_key = next;
|
||||
}
|
||||
break;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,157 @@
|
||||
[2J[001;001H[=3h[2J[001;001H[2J[001;001H[8;042;160t[2J[001;001H[2J[001;001H[8;056;240t[2J[001;001HBdsDxe: loading Boot0002 "UEFI QEMU DVD-ROM QM00005 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0)
|
||||
BdsDxe: starting Boot0002 "UEFI QEMU DVD-ROM QM00005 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0)
|
||||
[2J[001;001H[=3h[2J[001;001HStarKernel UEFI Loader
|
||||
Loading kernel from ESP...
|
||||
[CKPT 001] Entered efi_main - ConOut live
|
||||
RAW SERIAL UP
|
||||
[CKPT 002] Serial (COM1) initialized
|
||||
Monolithic build - kernel linked directly
|
||||
Collecting boot information...
|
||||
CmdLine: parsed OK
|
||||
[CKPT 004] Command line parsed
|
||||
[CKPT 005] Kernel stack allocation decided
|
||||
[CKPT 006] Boot info collected (ACPI table located)
|
||||
GOP: linear framebuffer found
|
||||
[CKPT 007] GOP: linear framebuffer found
|
||||
[CKPT 008] About to enter ExitBootServices retry loop
|
||||
EBS...
|
||||
EBS OK
|
||||
Calling kernel_main (monolithic)...
|
||||
|
||||
|
||||
_____ _ _ __ _
|
||||
/ ____| | | |/ / | |
|
||||
| (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| |
|
||||
\___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ |
|
||||
____) | || (_| | | | . \ __/ | | | | | __/ |
|
||||
|_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_|
|
||||
|
||||
LithosAnanke v2.1.0 amd64
|
||||
Architecture: amd64
|
||||
Build: Oct 26 2026 14:57:19
|
||||
|
||||
UEFI BootServices: EXITED
|
||||
Console: serial line is a 16550 at port 0x00000000000003f8 (COM1, probed)
|
||||
|
||||
=== StarKernel Boot Information ===
|
||||
Memory map entries: 131
|
||||
Total memory: 1023 MB
|
||||
Usable memory: 966 MB
|
||||
===================================
|
||||
|
||||
PMM initialized.
|
||||
PMM statistics:
|
||||
Total pages: 248676
|
||||
Free pages : 247153
|
||||
Used pages : 1523
|
||||
Total MB : 971
|
||||
Free MB : 965
|
||||
Used MB : 5
|
||||
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM self-test: mapped OK at 0xffff800000000000
|
||||
VMM self-test complete.
|
||||
|
||||
IDT installed.
|
||||
|
||||
APIC: init...
|
||||
APIC: IA32_APIC_BASE MSR=0x00000000fee00900
|
||||
APIC: stale-ISR drain: 0 EOI(s) issued
|
||||
APIC: initialized (xAPIC MMIO, TPR=0, SIVR=0x1FF, EOI-clear)
|
||||
APIC: init done
|
||||
|
||||
I/O APIC: init...
|
||||
I/O APIC: base=0xfec00000, gsi_base=0, overrides=5
|
||||
override: source=00 gsi=2 flags=0x0000
|
||||
override: source=05 gsi=5 flags=0x000d
|
||||
override: source=09 gsi=9 flags=0x000d
|
||||
override: source=0a gsi=10 flags=0x000d
|
||||
override: source=0b gsi=11 flags=0x000d
|
||||
i8042: keyboard ACKed enable-scanning
|
||||
i8042: IRQ1 enabled in controller config byte
|
||||
I/O APIC: keyboard IRQ1 routed (masked)
|
||||
|
||||
Timer: init...
|
||||
Timer: init start
|
||||
Timer: PM_TMR_BLK discovered from FADT at port 1544
|
||||
Timer: VM mode detected (hypervisor present).
|
||||
Timer: HPET calibration disabled (VM-exit MMIO would poison timing).
|
||||
Timer: WARNING: invariant TSC not present under hypervisor.
|
||||
Timer: continuing in RELATIVE mode (no determinism guarantees).
|
||||
Timer: RDTSCP not present; using RDTSC (less serialized).
|
||||
Timer: CPUID frequency unavailable; trying PM Timer...
|
||||
Timer: trust=1 (0=NONE,1=REL,2=ABS), TSC=2088386161 Hz
|
||||
Timer: init done
|
||||
|
||||
Kernel heap initialized.
|
||||
Heap statistics:
|
||||
Total bytes: 536870872
|
||||
Free bytes: 536870872
|
||||
Used bytes: 0
|
||||
Peak bytes: 0
|
||||
Heap base addr: 24641536
|
||||
Heap end addr: 561512448
|
||||
|
||||
Heartbeat: init...
|
||||
APIC Timer: calibrating...
|
||||
APIC Timer: apic_hz=1002641129, tick_hz=100, initial_count=10026411
|
||||
APIC Timer: configured (masked, ready to start)
|
||||
Heartbeat: init done
|
||||
Kernel initialization complete.
|
||||
Boot successful!
|
||||
|
||||
System: StarForth v4 (this build's default)
|
||||
StarForth v4: one host node, the F18-derived engine
|
||||
V4: capsule v4:sys:map-64.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:map-64.f18 capsule_hash=0x949eb6a1e9260e49
|
||||
V4: capsule v4:sys:core.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:core.f18 capsule_hash=0xb8f167892ec18c28
|
||||
V4: capsule v4:sys:input.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:input.f18 capsule_hash=0x85d3ec486d929a79
|
||||
V4: capsule v4:sys:dict.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:dict.f18 capsule_hash=0x1379bd3b5de811dc
|
||||
V4: capsule v4:sys:codegen.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:codegen.f18 capsule_hash=0x36d2ae84d2911b90
|
||||
V4: capsule v4:sys:compile.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:compile.f18 capsule_hash=0x11145c4c2ab819d8
|
||||
V4: capsule v4:sys:quit.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:quit.f18 capsule_hash=0x43cadf3b21ddbf3e
|
||||
V4: capsule v4:sys:forth.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:forth.f18 capsule_hash=0x16cab4a1268b85da
|
||||
V4: capsule v4:sys:numout.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:numout.f18 capsule_hash=0x85a240ad3fb2b299
|
||||
V4: capsule v4:sys:words.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:words.f18 capsule_hash=0xb1d381f927d9f14e
|
||||
V4: capsule v4:sys:system.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:system.f18 capsule_hash=0xd92203664c2915bd
|
||||
V4: capsule v4:sys:qmath.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:qmath.f18 capsule_hash=0xdb4140713dd857f3
|
||||
V4: capsule v4:sys:blocks.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:blocks.f18 capsule_hash=0x76307ef48678dc2a
|
||||
V4: capsule v4:sys:log.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:log.f18 capsule_hash=0xfc6540e6b824a52b
|
||||
V4: capsule v4:sys:acl.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:acl.f18 capsule_hash=0x6845aa048db7eb22
|
||||
V4: capsule v4:sys:end.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:end.f18 capsule_hash=0x5ef01312c07b79cc
|
||||
PARITY:V4_ROM words=2372 rom_hash=0x87b23d3ae2643c8d instructions=59145258
|
||||
V4: capsule v4:forth79.4th signature: missing (unsigned)
|
||||
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x033e1c05c09a1df8
|
||||
PARITY:V4_POST tests=538 pass=538 fail=0
|
||||
PARITY:V4_SYSTEM word_count=317 dict_hash=0xfec8c47cfc6f437f
|
||||
PARITY:OK
|
||||
POST: PASSED
|
||||
PCI: init...
|
||||
PCI: ECAM mapped (amd64)
|
||||
virtio-blk: found device
|
||||
Artemis: virtio-blk attached
|
||||
Starting heartbeat...
|
||||
APIC Timer: started (LVT=0x00020020 ICR=10026411)
|
||||
I/O APIC: keyboard IRQ1 unmasked
|
||||
Heartbeat running.
|
||||
blkio_usb: MSC device ready
|
||||
[38;2;255;165;0m[Hera][39m Zuse: identity confirmed from attached thumbdrive
|
||||
[38;2;255;165;0m[zuse@Hera][39m [38;2;85;255;255mok> [39m3 4 + .
|
||||
[38;2;255;165;0m[zuse@Hera][39m 7 ok
|
||||
[38;2;255;165;0m[zuse@Hera][39m [38;2;85;255;255mok> [39m
|
||||
@@ -0,0 +1,128 @@
|
||||
UEFI firmware (version 2025.11-3ubuntu7.3 built at 15:40:26 on Sep 23 2026)
|
||||
[2J[001;001H[=3h[2J[001;001H[2J[001;001H[8;031;100t[2J[001;001HBdsDxe: failed to load Boot0002 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x2,0x0): Not Found
|
||||
BdsDxe: failed to load Boot0003 "UEFI QEMU QEMU USB HARDDRIVE 1-0000:00:04.0-1" from PciRoot(0x0)/Pci(0x4,0x0)/USB(0x0,0x0): Not Found
|
||||
BdsDxe: loading Boot0004 "UEFI Misc Device 2" from PciRoot(0x0)/Pci(0x6,0x0)
|
||||
BdsDxe: starting Boot0004 "UEFI Misc Device 2" from PciRoot(0x0)/Pci(0x6,0x0)
|
||||
[2J[001;001H[=3h[2J[001;001HStarKernel UEFI Loader
|
||||
Loading kernel from ESP...
|
||||
[CKPT 001] Entered efi_main - ConOut live
|
||||
Collecting boot information...
|
||||
[CKPT 004] Command line parsed
|
||||
[CKPT 005] Kernel stack allocation decided
|
||||
[CKPT 006] Boot info collected (ACPI table located)
|
||||
[CKPT 007] GOP: linear framebuffer found
|
||||
[CKPT 008] About to enter ExitBootServices retry loop
|
||||
|
||||
|
||||
_____ _ _ __ _
|
||||
/ ____| | | |/ / | |
|
||||
| (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| |
|
||||
\___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ |
|
||||
____) | || (_| | | | . \ __/ | | | | | __/ |
|
||||
|_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_|
|
||||
|
||||
LithosAnanke v2.1.0 aarch64
|
||||
Architecture: aarch64
|
||||
Build: Oct 26 2026 14:58:53
|
||||
|
||||
UEFI BootServices: EXITED
|
||||
Console: serial line is a PL011 at 0x0000000009000000 (no devicetree: QEMU's)
|
||||
|
||||
=== StarKernel Boot Information ===
|
||||
Memory map entries: 108
|
||||
Total memory: 4093 MB
|
||||
Usable memory: 4054 MB
|
||||
===================================
|
||||
|
||||
PMM initialized.
|
||||
PMM statistics:
|
||||
Total pages: 1039284
|
||||
Free pages : 1037873
|
||||
Used pages : 1411
|
||||
Total MB : 4059
|
||||
Free MB : 4054
|
||||
Used MB : 5
|
||||
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM self-test: mapped OK at 0xffff800000000000
|
||||
VMM self-test complete.
|
||||
|
||||
AArch64: running at EL1
|
||||
IDT installed.
|
||||
|
||||
APIC: init...
|
||||
PSCI: no DTB -- using HVC (QEMU virt-machine default)
|
||||
GICv2: no DTB GIC node -- using QEMU virt-machine defaults
|
||||
GICv2: distributor+CPU interface enabled, PPI 30
|
||||
APIC: init done
|
||||
|
||||
Timer: init...
|
||||
Timer: AArch64 generic timer initialised.
|
||||
Timer: init done
|
||||
|
||||
Kernel heap initialized.
|
||||
Heap statistics:
|
||||
Total bytes: 2147483608
|
||||
Free bytes: 2147483608
|
||||
Used bytes: 0
|
||||
Peak bytes: 0
|
||||
Heap base addr: 1207959552
|
||||
Heap end addr: 3355443200
|
||||
|
||||
Heartbeat: init...
|
||||
Heartbeat: init done
|
||||
Kernel initialization complete.
|
||||
Boot successful!
|
||||
|
||||
System: StarForth v4 (this build's default)
|
||||
StarForth v4: one host node, the F18-derived engine
|
||||
V4: capsule v4:sys:map-64.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:map-64.f18 capsule_hash=0x949eb6a1e9260e49
|
||||
V4: capsule v4:sys:core.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:core.f18 capsule_hash=0xb8f167892ec18c28
|
||||
V4: capsule v4:sys:input.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:input.f18 capsule_hash=0x85d3ec486d929a79
|
||||
V4: capsule v4:sys:dict.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:dict.f18 capsule_hash=0x1379bd3b5de811dc
|
||||
V4: capsule v4:sys:codegen.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:codegen.f18 capsule_hash=0x36d2ae84d2911b90
|
||||
V4: capsule v4:sys:compile.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:compile.f18 capsule_hash=0x11145c4c2ab819d8
|
||||
V4: capsule v4:sys:quit.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:quit.f18 capsule_hash=0x43cadf3b21ddbf3e
|
||||
V4: capsule v4:sys:forth.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:forth.f18 capsule_hash=0x16cab4a1268b85da
|
||||
V4: capsule v4:sys:numout.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:numout.f18 capsule_hash=0x85a240ad3fb2b299
|
||||
V4: capsule v4:sys:words.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:words.f18 capsule_hash=0xb1d381f927d9f14e
|
||||
V4: capsule v4:sys:system.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:system.f18 capsule_hash=0xd92203664c2915bd
|
||||
V4: capsule v4:sys:qmath.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:qmath.f18 capsule_hash=0xdb4140713dd857f3
|
||||
V4: capsule v4:sys:blocks.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:blocks.f18 capsule_hash=0x76307ef48678dc2a
|
||||
V4: capsule v4:sys:log.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:log.f18 capsule_hash=0xfc6540e6b824a52b
|
||||
V4: capsule v4:sys:acl.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:acl.f18 capsule_hash=0x6845aa048db7eb22
|
||||
V4: capsule v4:sys:end.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:end.f18 capsule_hash=0x5ef01312c07b79cc
|
||||
PARITY:V4_ROM words=2372 rom_hash=0x87b23d3ae2643c8d instructions=59145258
|
||||
V4: capsule v4:forth79.4th signature: missing (unsigned)
|
||||
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x033e1c05c09a1df8
|
||||
PARITY:V4_POST tests=538 pass=538 fail=0
|
||||
PARITY:V4_SYSTEM word_count=317 dict_hash=0xfec8c47cfc6f437f
|
||||
PARITY:OK
|
||||
POST: PASSED
|
||||
PCI: init...
|
||||
virtio-blk: found device
|
||||
Artemis: virtio-blk attached
|
||||
Starting heartbeat...
|
||||
Heartbeat running.
|
||||
blkio_usb: MSC device ready
|
||||
[38;2;255;165;0m[Hera][39m Zuse: identity confirmed from attached thumbdrive
|
||||
[38;2;255;165;0m[zuse@Hera][39m [38;2;85;255;255mok> [39m3 4 + .
|
||||
[38;2;255;165;0m[zuse@Hera][39m 7 ok
|
||||
[38;2;255;165;0m[zuse@Hera][39m [38;2;85;255;255mok> [39m
|
||||
@@ -0,0 +1,199 @@
|
||||
|
||||
OpenSBI v1.8
|
||||
____ _____ ____ _____
|
||||
/ __ \ / ____| _ \_ _|
|
||||
| | | |_ __ ___ _ __ | (___ | |_) || |
|
||||
| | | | '_ \ / _ \ '_ \ \___ \| _ < | |
|
||||
| |__| | |_) | __/ | | |____) | |_) || |_
|
||||
\____/| .__/ \___|_| |_|_____/|____/_____|
|
||||
| |
|
||||
|_|
|
||||
|
||||
Platform Name : riscv-virtio,qemu
|
||||
Platform Features : medeleg
|
||||
Platform HART Count : 1
|
||||
Platform HART Protection : pmp
|
||||
Platform IPI Device : aclint-mswi
|
||||
Platform Timer Device : aclint-mtimer @ 10000000Hz
|
||||
Platform Console Device : uart8250
|
||||
Platform HSM Device : ---
|
||||
Platform PMU Device : ---
|
||||
Platform Reboot Device : syscon-reboot
|
||||
Platform Shutdown Device : syscon-poweroff
|
||||
Platform Suspend Device : ---
|
||||
Platform CPPC Device : ---
|
||||
Firmware Base : 0x80000000
|
||||
Firmware Size : 321 KB
|
||||
Firmware RW Offset : 0x40000
|
||||
Firmware RW Size : 65 KB
|
||||
Firmware Heap Offset : 0x47000
|
||||
Firmware Heap Size : 37 KB (total), 0 KB (reserved), 12 KB (used), 23 KB (free)
|
||||
Firmware Scratch Size : 4096 B (total), 1464 B (used), 2632 B (free)
|
||||
Runtime SBI Version : 3.0
|
||||
Standard SBI Extensions : ipi,pmu,srst,sse,hsm,rfnc,fwft,time,base,legacy,dbcn,dbtr
|
||||
Experimental SBI Extensions : none
|
||||
|
||||
Domain0 Name : root
|
||||
Domain0 Boot HART : 0
|
||||
Domain0 HARTs : 0*
|
||||
Domain0 Region00 : 0x0000000080040000-0x000000008005ffff M: (F,R,W) S/U: ()
|
||||
Domain0 Region01 : 0x0000000080000000-0x000000008003ffff M: (F,R,X) S/U: ()
|
||||
Domain0 Region02 : 0x0000000000100000-0x0000000000100fff M: (I,R,W) S/U: (R,W)
|
||||
Domain0 Region03 : 0x0000000010000000-0x0000000010000fff M: (I,R,W) S/U: (R,W)
|
||||
Domain0 Region04 : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: ()
|
||||
Domain0 Region05 : 0x000000000c400000-0x000000000c5fffff M: (I,R,W) S/U: (R,W)
|
||||
Domain0 Region06 : 0x000000000c000000-0x000000000c3fffff M: (I,R,W) S/U: (R,W)
|
||||
Domain0 Region07 : 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X)
|
||||
Domain0 Next Address : 0x0000000020000000
|
||||
Domain0 Next Arg1 : 0x00000000bfe00000
|
||||
Domain0 Next Mode : S-mode
|
||||
Domain0 SysReset : yes
|
||||
Domain0 SysSuspend : yes
|
||||
|
||||
Boot HART ID : 0
|
||||
Boot HART Domain : root
|
||||
Boot HART Priv Version : v1.12
|
||||
Boot HART Base ISA : rv64imafdch
|
||||
Boot HART ISA Extensions : sstc,zicntr,zihpm,zicboz,zicbom,sdtrig,svadu
|
||||
Boot HART PMP Count : 16
|
||||
Boot HART PMP Granularity : 2 bits
|
||||
Boot HART PMP Address Bits : 54
|
||||
Boot HART MHPM Info : 16 (0x0007fff8)
|
||||
Boot HART Debug Triggers : 2 triggers
|
||||
Boot HART MIDELEG : 0x0000000000001666
|
||||
Boot HART MEDELEG : 0x0000000000f4b509
|
||||
[2J[004D[=3h[2J[009D[2J[004D[8;031;100t[2J[016DRISC-V EDK2 firmware version 2025.11-3ubuntu7.3
|
||||
Press ESCAPE within 5 seconds for boot options ERROR: C40000002:V03051002 I0 6D33944A-EC75-4855-A54D-809C75241F6C 83FFF850
|
||||
BdsDxe: failed to load Boot0001 "UEFI Misc Device" fr
|
||||
om PciRoot(0x0)/Pci(0x1,0x0): Not Found
|
||||
[2J[001;001H[=3h[2J[009DStarKernel UEFI Loader
|
||||
Loading kernel from ESP...
|
||||
[CKPT 001] Entered efi_main - ConOut live
|
||||
Monolithic build - kernel linked directly
|
||||
Collecting boot information...
|
||||
CmdLine: parsed OK
|
||||
[CKPT 004] Command line parsed
|
||||
[CKPT 005] Kernel stack allocation decided
|
||||
[CKPT 006] Boot info collected (ACPI table located)
|
||||
GOP: linear framebuffer found
|
||||
[CKPT 007] GOP: linear framebuffer found
|
||||
[CKPT 008] About to enter ExitBootServices retry loop
|
||||
Calling kernel_main (monolithic)...
|
||||
riscv64 item 4.3.5a: satp state at kernel entry (before switch)
|
||||
satp.MODE = 0x000000000000000a
|
||||
satp.PPN = 0x00000000000bf868
|
||||
__kernel_start = 0x00000000bdc2a644
|
||||
riscv64: satp cleared -- Bare mode, explicit (item 4.3.5a)
|
||||
|
||||
|
||||
_____ _ _ __ _
|
||||
/ ____| | | |/ / | |
|
||||
| (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| |
|
||||
\___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ |
|
||||
____) | || (_| | | | . \ __/ | | | | | __/ |
|
||||
|_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_|
|
||||
|
||||
LithosAnanke v2.1.0 riscv64
|
||||
Architecture: riscv64
|
||||
Build: Oct 26 2026 15:02:23
|
||||
|
||||
UEFI BootServices: EXITED
|
||||
Console: serial line is a 16550 at 0x0000000010000000 (no devicetree: QEMU's)
|
||||
|
||||
=== StarKernel Boot Information ===
|
||||
Memory map entries: 100
|
||||
Total memory: 1020 MB
|
||||
Usable memory: 974 MB
|
||||
===================================
|
||||
|
||||
PMM initialized.
|
||||
PMM statistics:
|
||||
Total pages: 250205
|
||||
Free pages : 249553
|
||||
Used pages : 652
|
||||
Total MB : 977
|
||||
Free MB : 974
|
||||
Used MB : 2
|
||||
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM initialized (mapped RAM, CR3 switched)
|
||||
VMM self-test: mapped OK at 0xffff800000000000
|
||||
VMM self-test complete.
|
||||
|
||||
IDT installed.
|
||||
|
||||
APIC: init...
|
||||
PLIC: no DTB PLIC node -- using QEMU virt-machine default (base=0x0c000000)
|
||||
PLIC: init (S-mode context 1, threshold=0)
|
||||
APIC: init done
|
||||
|
||||
Timer: init...
|
||||
Timer: RISC-V time CSR @ 10000000 Hz (FALLBACK, no devicetree)
|
||||
Timer: init done
|
||||
|
||||
Kernel heap initialized.
|
||||
Heap statistics:
|
||||
Total bytes: 536870872
|
||||
Free bytes: 536870872
|
||||
Used bytes: 0
|
||||
Peak bytes: 0
|
||||
Heap base addr: 2214588416
|
||||
Heap end addr: 2751459328
|
||||
|
||||
Heartbeat: init...
|
||||
Heartbeat: init done
|
||||
Kernel initialization complete.
|
||||
Boot successful!
|
||||
|
||||
System: StarForth v4 (this build's default)
|
||||
StarForth v4: one host node, the F18-derived engine
|
||||
V4: capsule v4:sys:map-64.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:map-64.f18 capsule_hash=0x949eb6a1e9260e49
|
||||
V4: capsule v4:sys:core.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:core.f18 capsule_hash=0xb8f167892ec18c28
|
||||
V4: capsule v4:sys:input.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:input.f18 capsule_hash=0x85d3ec486d929a79
|
||||
V4: capsule v4:sys:dict.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:dict.f18 capsule_hash=0x1379bd3b5de811dc
|
||||
V4: capsule v4:sys:codegen.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:codegen.f18 capsule_hash=0x36d2ae84d2911b90
|
||||
V4: capsule v4:sys:compile.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:compile.f18 capsule_hash=0x11145c4c2ab819d8
|
||||
V4: capsule v4:sys:quit.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:quit.f18 capsule_hash=0x43cadf3b21ddbf3e
|
||||
V4: capsule v4:sys:forth.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:forth.f18 capsule_hash=0x16cab4a1268b85da
|
||||
V4: capsule v4:sys:numout.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:numout.f18 capsule_hash=0x85a240ad3fb2b299
|
||||
V4: capsule v4:sys:words.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:words.f18 capsule_hash=0xb1d381f927d9f14e
|
||||
V4: capsule v4:sys:system.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:system.f18 capsule_hash=0xd92203664c2915bd
|
||||
V4: capsule v4:sys:qmath.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:qmath.f18 capsule_hash=0xdb4140713dd857f3
|
||||
V4: capsule v4:sys:blocks.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:blocks.f18 capsule_hash=0x76307ef48678dc2a
|
||||
V4: capsule v4:sys:log.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:log.f18 capsule_hash=0xfc6540e6b824a52b
|
||||
V4: capsule v4:sys:acl.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:acl.f18 capsule_hash=0x6845aa048db7eb22
|
||||
V4: capsule v4:sys:end.f18 signature: missing (unsigned)
|
||||
PARITY:V4_F18 name=v4:sys:end.f18 capsule_hash=0x5ef01312c07b79cc
|
||||
PARITY:V4_ROM words=2372 rom_hash=0x87b23d3ae2643c8d instructions=59145258
|
||||
V4: capsule v4:forth79.4th signature: missing (unsigned)
|
||||
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x033e1c05c09a1df8
|
||||
PARITY:V4_POST tests=538 pass=538 fail=0
|
||||
PARITY:V4_SYSTEM word_count=317 dict_hash=0xfec8c47cfc6f437f
|
||||
PARITY:OK
|
||||
POST: PASSED
|
||||
PCI: init...
|
||||
virtio-blk: found device
|
||||
Artemis: virtio-blk attached
|
||||
Starting heartbeat...
|
||||
SBI: timer armed (TIME extension)
|
||||
Heartbeat running.
|
||||
blkio_usb: MSC device ready
|
||||
[38;2;255;165;0m[Hera][39m Zuse: identity confirmed from attached thumbdrive
|
||||
[38;2;255;165;0m[zuse@Hera][39m [38;2;85;255;255mok> [39m3 4 + .
|
||||
[38;2;255;165;0m[zuse@Hera][39m 7 ok
|
||||
[38;2;255;165;0m[zuse@Hera][39m [38;2;85;255;255mok> [39m
|
||||
Executable
+273
@@ -0,0 +1,273 @@
|
||||
#!/usr/bin/env python3
|
||||
"""qemu_session.py -- one typed QEMU session against a kernel boot, and its verdict.
|
||||
|
||||
scripts/qemu_session.py MODE ARCH [--label L] [--make "VAR=val ..."] [--no-zuse]
|
||||
|
||||
Builds and boots `make ARCH=<arch> clean qemu` (one QEMU, in the foreground of
|
||||
this script), with copies of the minted Zuse pair (disk/zuse-scratch/) made
|
||||
under build/qemu-session/<label>/ so the committed images are never booted.
|
||||
It reads the serial socket continuously, drives the boot over the serial and
|
||||
QMP sockets the `qemu` goal opens, prints PASS:/FAIL: lines and
|
||||
RESULT: PASS|FAIL, and quits QEMU over QMP. The serial log is the usual
|
||||
logs/<TS>/<arch>/qemu-<arch>-<TS>.log.
|
||||
|
||||
Modes (the identity gate's, plan 2026-10-26-engine-step4-identity-gate.md, and
|
||||
the stick's, plan 2026-10-26-stick-1-screen-and-keyboard.md):
|
||||
headless no Zuse drive: POST: PASSED, then no `ok> ` for 60 s
|
||||
zuse the minted pair: identity confirmed, [zuse@Hera] ok>, `3 4 + .` -> 7 ok
|
||||
hotplug no drive; Zuse added over QMP -> prompt; pulled -> session ended,
|
||||
headless; added again -> prompt
|
||||
midpull pulled while a line is in hand: what is typed after does not run
|
||||
waitpull pulled while a line WAITS: the wait ends at logout; re-attach -> prompt
|
||||
typeahead serial bytes typed while headless do not run once Zuse attaches
|
||||
emergency an EMERGENCY_CONSOLE_ENABLED=1 build: ok> with no drive
|
||||
v3_keys system=v3: `3 4 + .` typed on QEMU's keyboard (send-key) -> 7 ok
|
||||
|
||||
Needs only Python 3. One QEMU at a time (.claude/CLAUDE.md).
|
||||
"""
|
||||
import argparse, glob, json, os, re, shutil, socket, subprocess, sys, threading, time
|
||||
|
||||
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
||||
PROMPT = r"\[zuse@Hera\][^\n]*ok> "
|
||||
ANYPROMPT = r"ok> "
|
||||
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("mode")
|
||||
ap.add_argument("arch")
|
||||
ap.add_argument("--label", default=None)
|
||||
ap.add_argument("--make", default="")
|
||||
ap.add_argument("--no-zuse", action="store_true")
|
||||
a = ap.parse_args()
|
||||
|
||||
NO_ZUSE_MODES = {"headless", "hotplug", "midpull", "waitpull", "typeahead", "emergency"}
|
||||
label = a.label or f"{a.mode}-{a.arch}"
|
||||
work = os.path.join(ROOT, "build", "qemu-session", label)
|
||||
shutil.rmtree(work, ignore_errors=True)
|
||||
os.makedirs(work)
|
||||
for f in ("artemis.img", "zuse-thumb-ident.img"):
|
||||
subprocess.run(["cp", "--sparse=always", os.path.join(ROOT, "disk/zuse-scratch", f), work], check=True)
|
||||
art = os.path.join(work, "artemis.img")
|
||||
zimg = os.path.join(work, "zuse-thumb-ident.img")
|
||||
attach_zuse = not (a.no_zuse or a.mode in NO_ZUSE_MODES)
|
||||
|
||||
make_args = ["make", f"ARCH={a.arch}", "clean", "qemu", f"ARTDISK={art}",
|
||||
f"ZUSEDISK={zimg if attach_zuse else ''}"] + a.make.split()
|
||||
if a.mode == "v3_keys":
|
||||
make_args.append("KERNEL_ARGS=system=v3")
|
||||
start = time.time()
|
||||
make_log = open(os.path.join(work, "make.txt"), "w")
|
||||
mk = subprocess.Popen(make_args, cwd=ROOT, stdout=make_log, stderr=subprocess.STDOUT)
|
||||
deadline = time.time() + 1800
|
||||
ok = True
|
||||
|
||||
|
||||
def newest(pattern):
|
||||
c = [p for p in glob.glob(pattern) if os.path.getmtime(p) >= start]
|
||||
return max(c, key=os.path.getmtime) if c else None
|
||||
|
||||
|
||||
log = ser = qmp = None
|
||||
while time.time() < deadline and not (log and ser and qmp):
|
||||
if mk.poll() is not None:
|
||||
print(f"MAKE FAILED (exit {mk.returncode}); see {make_log.name}", flush=True)
|
||||
sys.exit(1)
|
||||
log = log or newest(f"{ROOT}/logs/*/{a.arch}/qemu-{a.arch}-*.log")
|
||||
ser = ser or newest(f"{ROOT}/build/{a.arch}/kernel/qemu-serial-{a.arch}-*.sock")
|
||||
qmp = qmp or newest(f"{ROOT}/build/{a.arch}/kernel/qemu-qmp-{a.arch}-*.sock")
|
||||
time.sleep(1)
|
||||
print(f"LOG: {os.path.relpath(log, ROOT)}", flush=True)
|
||||
|
||||
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
for _ in range(60):
|
||||
try:
|
||||
s.connect(ser)
|
||||
break
|
||||
except OSError:
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
def drain():
|
||||
while True:
|
||||
try:
|
||||
if not s.recv(4096):
|
||||
return
|
||||
except OSError:
|
||||
return
|
||||
|
||||
|
||||
threading.Thread(target=drain, daemon=True).start()
|
||||
|
||||
q = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
q.connect(qmp)
|
||||
qf = q.makefile("r")
|
||||
qf.readline()
|
||||
|
||||
|
||||
def qcmd(cmd, **args):
|
||||
msg = {"execute": cmd}
|
||||
if args:
|
||||
msg["arguments"] = args
|
||||
q.send(json.dumps(msg).encode())
|
||||
while True:
|
||||
r = json.loads(qf.readline())
|
||||
if "return" in r or "error" in r:
|
||||
if "error" in r:
|
||||
print(f"QMP {cmd}: {json.dumps(r)}", flush=True)
|
||||
return r
|
||||
|
||||
|
||||
qcmd("qmp_capabilities")
|
||||
|
||||
|
||||
def text():
|
||||
with open(log, errors="replace") as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
def count(pat):
|
||||
return len(re.findall(pat, text()))
|
||||
|
||||
|
||||
def wait_for(pat, secs, after=0):
|
||||
t = time.time()
|
||||
while time.time() - t < secs:
|
||||
if count(pat) > after:
|
||||
return True
|
||||
if "POST: FAILED" in text() or "PARITY:FAIL" in text():
|
||||
return False
|
||||
time.sleep(0.5)
|
||||
return False
|
||||
|
||||
|
||||
def check(name, cond):
|
||||
global ok
|
||||
print(f"{'PASS' if cond else 'FAIL'}: {name}", flush=True)
|
||||
ok = ok and cond
|
||||
|
||||
|
||||
def type_line(line):
|
||||
"""Over the serial line, a character at a time."""
|
||||
for ch in line:
|
||||
s.send(ch.encode())
|
||||
time.sleep(0.05)
|
||||
s.send(b"\r")
|
||||
|
||||
|
||||
# QEMU qcodes for what the tests type on a keyboard
|
||||
QCODE = {" ": ["spc"], ".": ["dot"], "+": ["shift", "equal"], "-": ["minus"], "\n": ["ret"]}
|
||||
|
||||
|
||||
def key_line(line):
|
||||
"""On QEMU's keyboard (send-key), a key at a time."""
|
||||
for ch in line + "\n":
|
||||
keys = QCODE.get(ch, [ch.lower()])
|
||||
qcmd("send-key", keys=[{"type": "qcode", "data": k} for k in keys])
|
||||
time.sleep(0.1)
|
||||
|
||||
|
||||
def add_zuse(n):
|
||||
qcmd("blockdev-add", driver="raw", **{"node-name": f"zuse{n}"},
|
||||
file={"driver": "file", "filename": zimg})
|
||||
qcmd("device_add", driver="usb-storage", bus="xhci0.0", port="1",
|
||||
drive=f"zuse{n}", id=f"zusedev{n}")
|
||||
|
||||
|
||||
def del_zuse(n):
|
||||
qcmd("device_del", id=f"zusedev{n}")
|
||||
time.sleep(3)
|
||||
qcmd("blockdev-del", **{"node-name": f"zuse{n}"})
|
||||
|
||||
|
||||
check("POST: PASSED", wait_for(r"POST: PASSED", 900))
|
||||
m = a.mode
|
||||
|
||||
if m == "headless":
|
||||
check("no ok> for 60 s after POST", not wait_for(ANYPROMPT, 60))
|
||||
|
||||
elif m == "zuse":
|
||||
check("Zuse: identity confirmed", wait_for(r"Zuse: identity confirmed from attached thumbdrive", 120))
|
||||
check("[zuse@Hera] ok>", wait_for(PROMPT, 60))
|
||||
n = count(PROMPT)
|
||||
type_line("3 4 + .")
|
||||
check("7 ok, and a prompt", wait_for(PROMPT, 60, n) and re.search(r"7\s+ok", text()) is not None)
|
||||
|
||||
elif m == "hotplug":
|
||||
check("no ok> for 20 s with no drive", not wait_for(ANYPROMPT, 20))
|
||||
add_zuse(1)
|
||||
check("identity confirmed on attach", wait_for(r"Zuse: identity confirmed from attached thumbdrive", 120))
|
||||
check("[zuse@Hera] ok> after attach", wait_for(PROMPT, 60))
|
||||
n = count(PROMPT)
|
||||
type_line("3 4 + .")
|
||||
check("7 ok", wait_for(PROMPT, 60, n) and re.search(r"7\s+ok", text()) is not None)
|
||||
del_zuse(1)
|
||||
check("session ended on detach", wait_for(r"Zuse: session ended -- reattach to re-authenticate", 60))
|
||||
n = count(ANYPROMPT)
|
||||
check("no new ok> for 30 s after detach", not wait_for(ANYPROMPT, 30, n))
|
||||
c = count(r"Zuse: identity confirmed from attached thumbdrive")
|
||||
p = count(PROMPT)
|
||||
add_zuse(2)
|
||||
check("identity confirmed on re-attach", wait_for(r"Zuse: identity confirmed from attached thumbdrive", 120, c))
|
||||
check("[zuse@Hera] ok> again", wait_for(PROMPT, 60, p))
|
||||
|
||||
elif m == "midpull":
|
||||
add_zuse(1)
|
||||
check("[zuse@Hera] ok> after attach", wait_for(PROMPT, 120))
|
||||
qcmd("device_del", id="zusedev1")
|
||||
type_line("3 4 + .")
|
||||
type_line("5 6 + .")
|
||||
check("session ended on detach", wait_for(r"Zuse: session ended -- reattach to re-authenticate", 60))
|
||||
time.sleep(10)
|
||||
t = text()
|
||||
check("the line typed after the pull did not run (no 11)", re.search(r"\b11\s+ok", t) is None)
|
||||
check("no ok> after the session ended", "ok> " not in t[t.rfind("Zuse: session ended"):])
|
||||
|
||||
elif m == "waitpull":
|
||||
add_zuse(1)
|
||||
check("[zuse@Hera] ok> after attach", wait_for(PROMPT, 120))
|
||||
type_line("5 AWAIT")
|
||||
time.sleep(5)
|
||||
del_zuse(1)
|
||||
check("session ended on detach", wait_for(r"Zuse: session ended -- reattach to re-authenticate", 60))
|
||||
check("the waiting line ended at logout (Interrupted)", wait_for(r"Interrupted", 30))
|
||||
p = count(PROMPT)
|
||||
add_zuse(2)
|
||||
check("identity confirmed on re-attach", wait_for(r"Zuse: identity confirmed from attached thumbdrive", 120, 1))
|
||||
check("[zuse@Hera] ok> again", wait_for(PROMPT, 60, p))
|
||||
n = count(PROMPT)
|
||||
type_line("3 4 + .")
|
||||
check("7 ok after re-attach", wait_for(PROMPT, 60, n) and re.search(r"7\s+ok", text()) is not None)
|
||||
|
||||
elif m == "typeahead":
|
||||
check("no ok> for 10 s with no drive", not wait_for(ANYPROMPT, 10))
|
||||
type_line("3 4 + .")
|
||||
time.sleep(5)
|
||||
add_zuse(1)
|
||||
check("[zuse@Hera] ok> after attach", wait_for(PROMPT, 120))
|
||||
time.sleep(5)
|
||||
check("what was typed while headless did not run (no 7)", re.search(r"\b7\s+ok", text()) is None)
|
||||
n = count(PROMPT)
|
||||
type_line("1 2 + .")
|
||||
check("3 ok typed at the prompt", wait_for(PROMPT, 60, n) and re.search(r"\b3\s+ok", text()) is not None)
|
||||
|
||||
elif m == "emergency":
|
||||
check("ok> with no drive", wait_for(ANYPROMPT, 60))
|
||||
n = count(ANYPROMPT)
|
||||
type_line("3 4 + .")
|
||||
check("7 ok", wait_for(ANYPROMPT, 60, n) and re.search(r"7\s+ok", text()) is not None)
|
||||
|
||||
elif m == "v3_keys":
|
||||
check("[zuse@Hera] ok>", wait_for(PROMPT, 300))
|
||||
time.sleep(2)
|
||||
n = count(PROMPT)
|
||||
key_line("3 4 + .")
|
||||
check("7 ok typed on the keyboard", wait_for(PROMPT, 60, n) and re.search(r"7\s+ok", text()) is not None)
|
||||
|
||||
else:
|
||||
check(f"known mode {m}", False)
|
||||
|
||||
print(f"RESULT: {'PASS' if ok else 'FAIL'}", flush=True)
|
||||
q.send(json.dumps({"execute": "quit"}).encode())
|
||||
mk.wait()
|
||||
for f in ("v3/include/version.h", "capsules/BLOCK_MAP.md"):
|
||||
subprocess.run(["git", "checkout", "-q", "--", f], cwd=ROOT)
|
||||
sys.exit(0 if ok else 2)
|
||||
Reference in New Issue
Block a user