- Home
- Getting Started
- Kernel Shell
Kernel Shell¶
The kernel shell is the interactive command-line interface running as task slot 3 (keyboard_loop in src/input/keyboard.rs). It is started during init::process::setup_processes and runs for the lifetime of the kernel (or till killed).
The purpose of having the kernel shell present is to provide a diagnostic command-line interface (CLI) when the system's state needs to be looked at. It is not intended to use the kernel shell as the main system shell: usage of the SH.ELF shell or a remote TNT.ELF shell instead is encouraged (see the Application Suite page for more info).
The kernel shell should be considered to be the system rescue shell primarily.
Userland Shell and Tunnel Probes¶
Console sh, Memento's Shell window (sh --host) and the TNT remote shell share the C bsh commands. With an active WireGuard daemon, their ping <IPv4> and traceroute <IPv4> builtins probe hosts in the peer's AllowedIPs prefixes using the tunnel source address. They accept numeric IPv4 addresses and allow one probe client at a time.
These commands belong to the userland shells. To use them from the text kernel's rescue shell, start fg sh first. In the graphics kernel, open Memento's Shell window. Use bg wgd --check <config> to validate a configuration there and read /mnt/tmp/WGD.LOG for its result; after starting bg wgd <config>, wait for the log's listening message before probing. See the WireGuard guide for the complete sequence and startup diagnostics.
Shell Loop¶
keyboard_loop() runs in an infinite loop:
- Print the prompt via
config::get_prompt()
user@host:path >
- Read characters from
SCANCODE_BUF(Set 1 scancodes, translated to ASCII). Buffer capacity: 128 bytes. -
Special keys handled inline:
- Enter — dispatch the accumulated input to
cmd::handle(input), then clear the buffer. - Backspace — remove the last character from the buffer and erase it from the display.
- Tab — attempt FAT12 prefix completion (see below).
- Ctrl+L — clear the screen (
clear_screen!()).
- Enter — dispatch the accumulated input to
-
Printable characters are echoed and appended to the input buffer.
The shell never exits. Starting a foreground process (fg) records the shell as the child's waiter and parks it (Idle); it is woken when that child exits, is killed or crashes — not when some unrelated background process ends. See Scheduler.
Tab Completion¶
When Tab is pressed, the current input is treated as a filename prefix. The shell scans the current FAT12 directory (via for_each_entry) for entries whose 8.3 name starts with the uppercased prefix. If exactly one match exists, the buffer is replaced with the lowercased match name. Multiple matches are printed but the buffer is left unchanged.
Nothing is completed while the working directory is on no FAT12 volume: /, /mnt, the ISO or the archive.
Command Dispatch¶
cmd::handle(input: &[u8]):
split_cmd(input)splits on the first space →(cmd_name, args).- Linear search through
COMMANDSfor an exact name match. - If found: calls
cmd.function(args). - If not found and input is non-empty: prints
Unknown command: <name>.
split_cmd is also used by individual command implementations to parse their own arguments.
The Root Directory¶
/ is the root of the VFS mount table, not a disk. It and /mnt hold nothing but the way to the mounted filesystems: dir lists what is mounted below them, cd moves through them, and the commands that work on files (read, rm, write, mkdir, mv) refuse to work there. The shell starts at /, so the first dir after boot shows mnt. Every file lives below a mount:
| Path | Filesystem | Mounted |
|---|---|---|
/mnt/fat |
the FAT12 floppy | only when a FAT12 floppy was found at boot |
/mnt/tmp |
the RAM disk, FAT16, a sixteenth of the RAM | when at least 2 MiB can be placed (empty at every boot; FAT12 at 2 MiB) |
/mnt/iso |
the CD, ISO9660, read-only | when a CD is found |
/mnt/tar |
the boot medium archive, read-only | when GRUB loaded one |
A bare path under / used to name the floppy's root: dir at / listed the floppy, and write there wrote to it. Booted from a USB stick, with no floppy, that was a directory that could only answer with disk errors. The filesystem syscalls now use the same mount-based resolution; see
Filesystem Overview.
Built-in Commands¶
Commands marked hidden do not appear in help output.
beep¶
Plays the built-in MIDI melody via the PC speaker (audio::midi::play_melody), then stops the speaker.
bg <binary>¶
Loads and runs an ELF binary in the background (shell remains interactive).
A bare name searches /mnt/tmp/jug first for Jug updates, then the
working directory, /mnt/tar/bin and /mnt/iso/bin. .elf is appended when
there is no extension; use an 8-character program basename.
The rescue shell limits the executable token to 8 characters, including any
extension, so use the short program name here. The underlying ELF loader and
syscall 0x2a also
support absolute paths up to 63 characters, without changing the working
directory; use that interface from userland for explicit path selection.
bg eth
bg garn --config /mnt/fat/GARN/GARN.CFG
fg <binary>¶
Same as bg but runs in the foreground — the shell blocks until the process exits.
fg sh
cd <path>¶
Changes the current working directory. Updates SYSTEM_CONFIG.path and path_cluster.
The argument is joined onto the current path and . and .. are collapsed
before anything is looked up, so a relative name is always resolved on the
filesystem the working directory sits on.
cd /— reset to the VFS root (see The Root Directory).cd /mnt— the directory holding the mount points.cd ..— go to parent; at the root it stays at the root.cd <name>— relative to the current directory: a mount point, or a directory on FAT12 or ISO9660.cd /mnt/fat/<path>— absolute FAT12 path (only with a FAT12 floppy).cd /mnt/tmp/<path>— absolute path on the FAT16 RAM disk.cd /mnt/iso/<path>— absolute ISO9660 path (validates directory exists).
Multi-component paths (foo/bar, ../bar) are supported. A path that is neither /, nor on the way to a mount, nor on a mounted filesystem is refused with no such directory.
The working directory is kept in a 32-byte field that userland also reads back
through sysinfo, so a path longer than that is refused with cd: path too
long instead of being stored truncated.
cls¶
Clears the screen (fills framebuffer/VGA buffer with black).
debug (hidden)¶
Writes the in-memory debug log (debug!/debugln!, 8 KiB) to DEBUG.TXT in the floppy's root when there is a FAT12 floppy, to /mnt/tmp/KERNDBG.LOG on the RAM disk, and to the serial port (COM1). Each file is replaced, so KERNDBG.LOG written at boot (see Init) is brought up to date.
debug
read /mnt/tmp/KERNDBG.LOG
dir [path]¶
Lists directory contents. Without an argument: lists the current working directory. With a path argument: lists that directory (absolute or relative, FAT12 or ISO9660).
A path argument is resolved exactly as cd resolves one: joined onto the
working directory when it is relative, with . and .. collapsed first.
Output format: one entry per line, directories have a trailing /.
dir
dir /mnt/iso
dir GFX
dir games
dir ../bin
At / and /mnt it lists the mount table instead: a directory on the way to mounts as [ DIR ], a mount point as [MOUNT] with its filesystem type, as mount names it. On a machine without a floppy, fat is not there.
root@rourex:/ > dir
mnt [ DIR ]
root@rourex:/ > cd mnt
root@rourex:/mnt > dir
fat [MOUNT] fat12
tmp [MOUNT] memdisk
iso [MOUNT] iso9660
tar [MOUNT] tar
echo <text>¶
Prints the argument string followed by a newline.
echo hello world
fsck¶
Runs the FAT12 filesystem check (fs::fat12::check::run_check). Prints a report with error count, orphaned clusters, cross-linked clusters, and invalid entries.
hda¶
What the HD Audio driver found: the controller's PCI address and ids, whether commands go through CORB/RIRB or the immediate registers, the codec, its audio function group, and the DACs and output pins in use (line out, speaker, headphones); while a stream plays, its rate and how much has been played, is queued, and how often it ran dry. hda tone plays a second of 440 Hz, which is the quickest way to hear whether sound works on a machine. See HD Audio.
help¶
Lists all non-hidden commands with their one-line descriptions.
heap¶
Prints the userland heap (initially 4 MiB at 0xC00000, plus its extension
when it has grown; see Allocators): used and free bytes, the largest free block, block counts, and the bytes held per scheduler slot (- for untagged blocks). A slot with bytes here but no entry in ts is a leak that outlived its process.
When the heap lock is busy the command prints which slot holds it instead — a heap that stays busy is one whose holder died holding it.
Userland heap (4 MiB at 0xC00000)
used 20480
free 4173800
largest free 4173800
blocks 3 (1 free)
slot 5 16384
slot 6 4096
hlt¶
Powers the machine off (ACPI S5). The sleep type comes from the \_S5_ package in the DSDT and goes to the PM1a/PM1b control ports the FADT names; if the firmware has not switched to ACPI mode yet, the kernel asks it to first (SMI_CMD ← ACPI_ENABLE). Without usable tables it falls back to the fixed QEMU/Bochs ports, then halts. See src/acpi/.
reboot¶
Restarts the machine: the FADT's reset register when the firmware has one, then the chipset's reset control port (0xCF9), then the keyboard controller (0x64 ← 0xFE), and last a triple fault.
nic¶
Lists PCI network controllers even before ETH registers, including primary
vendor/device IDs, subsystem IDs, BAR0 and available driver backends. After
eth starts, it shows the selected NIC, MAC, driver slot and packet counters.
Intel cards also report link speed/duplex, PHY state, hardware counters and
descriptor-ring positions. Broadcom BCM57765 reports its initialization
stage, firmware mailbox, PHY, negotiated link and packet-ring indices.
The command refreshes /mnt/tmp/NETINFO.TXT, which is also generated at boot
and after ETH registration. This product includes software developed by Bill Paul.
Intel diagnostics accept decimal numbers or hexadecimal with 0x:
nic reset # reinitialise the card
nic reset phy # also reset the PHY; link recovery takes time
nic tx # queue one test frame and show descriptor progress
nic reg <offset> [value]
nic phy <page> <register> [value]
nic nvm <word> # read a PCH flash NVM word
reg and phy read when no value is supplied, or write and read back when one is supplied. These operations, including reset and test transmission, require the Intel backend; RTL8139 still has the basic card and routing-counter display.
acpi¶
Shows what hlt and reboot will use on this machine: the root table GRUB passed, the PM1 control ports, the ACPI mode switch, the \_S5_ sleep types and the reset register. Useful to photograph when power-off or restart does not work on a particular board.
usb¶
Lists the USB host controllers on the PCI bus (UHCI, OHCI, EHCI, xHCI) and whether the firmware still drives them: firmware when it holds the controller (EHCI/xHCI's BIOS-owned semaphore, OHCI's interrupt routing, UHCI's port 60h/64h traps), and whether the controller can raise SMIs. On Intel cores from Nehalem on it also prints the number of SMIs taken since power-on (MSR_SMI_COUNT).
00:14.0 xHCI 8086:a36d firmware, SMIs on
SMIs since power-on: 5214
R2 has a native xHCI USB keyboard driver,
enabled automatically on EFI boots or explicitly with usb=xhci. Other USB
input still depends on firmware PS/2 emulation from System Management Mode.
Events handled by that firmware can raise SMIs, stopping the whole machine
regardless of PIC masks. If the SMI count jumps across a USB-related freeze,
the freeze happened in the firmware.
usb take stops the native keyboard driver, asks for controller ownership and
waits up to a second, takes it anyway if the firmware does not answer
(taken by force), disables SMIs, and stops every controller. USB input stops
until the next boot. The usb=os kernel option performs the same ownership-only
handoff at boot (see Taking USB from the Firmware).
kill <pid>¶
Kills the process with the given PID — the number ts prints — via task::scheduler::kill_by_id. PIDs are not slots: slots are reused, PIDs are not. Its page tables and heap blocks are released and a launcher waiting on it is woken. Prints kill: no such PID if nothing live has that PID.
kill 3
meminfo¶
Prints the total usable RAM reported by the Multiboot2 memory map at boot.
Total RAM: 2047 MiB (2146959360 bytes)
mkdir <dirname>¶
Creates a subdirectory in the current FAT12 directory. Name is uppercased to 8.3 format. Maximum name length: 11 bytes. Refused with not on a writable volume when the working directory is on no FAT12 volume (/, /mnt, the ISO or the archive).
mkdir MYDIR
mount¶
Lists all active VFS mount table entries, one line per mount: <path> (<fstype>[, <format>][, <size>][, <free> free]). The format is there when it says more than the type (the RAM disk is a memdisk and fat16); the size is the whole volume, and the free space is shown on the writable ones. Sizes are in whole MiB from 10 MiB, in KiB from 10 KiB. See Mount Sizes. /mnt/fat is there only when a FAT12 floppy was found at boot.
/ (rootfs)
/mnt/fat (fat12, 1440 KiB, 1338 KiB free)
/mnt/tmp (memdisk, fat16, 126 MiB, 125 MiB free)
/mnt/iso (iso9660, 112 MiB)
/mnt/tar (tar, 48 MiB)
mv <old> <new>¶
Renames a file in the current FAT12 directory. Both names are converted to 8.3 format. Does not change the file's data or cluster chain. Refused with not on a writable volume outside a FAT12 volume, as mkdir is.
mv FOO.TXT BAR.TXT
read <filename>¶
Prints the contents of a file. Supports both FAT12 (relative or absolute) and ISO9660 paths. Reads up to 4096 bytes; a longer file is cut short. A name that lies on no mounted filesystem (a bare name at /, say) answers no such file.
read HELLO.TXT
read /mnt/fat/GARN/INDEX.HTM
read /mnt/tmp/SUB/NOTE.TXT
read /mnt/iso/readme.txt
reset¶
Force resets the VGA video mode to 0x03 (text mode).
rm <filename>¶
Deletes a file from the current FAT12 directory: its cluster chain is returned to the FAT, then the directory entry is marked 0xE5 (deleted). Directories are not matched. Outside a FAT12 volume it answers no such file; it used to delete from the floppy's root there, even with the working directory on the ISO.
rm OLD.TXT
run <binary> (hidden)¶
Runs an ELF binary in the foreground. Unlike fg's 8-character limit, run
accepts an executable token of up to 12 characters. Arguments after the token
do not count towards that limit.
time¶
Reads the real-time clock (RTC/CMOS) and prints the current UTC time and date.
RTC Time: 14:32:07
RTC Date: 08/05/2026
ts¶
Lists all currently running tasks via task::scheduler::list_processes: one line per occupied scheduler slot with the slot, PID, name, mode (K/U) and status. Crashed processes stay listed until their slot is needed.
SLOT PID NAME M STATUS
0 0 kmain K (Running)
2 2 kclock K (Ready)
3 3 kshell K (Ready)
4 7 eth U (Blocked)
uptime (hidden)¶
Prints system uptime in hours, minutes, and seconds using the PIT tick counter.
Uptime: 0 hours 3 minutes 41 seconds
ver¶
Prints the kernel version string.
Version: 0.11.0
write <name> <text>¶
Writes <text> to <NAME>.TXT in the current FAT12 directory, replacing the file if it exists. The name is at most 8 characters, and .TXT is always appended. It works on the floppy and on the RAM disk at /mnt/tmp, and is refused with not on a writable volume anywhere else.
cd /mnt/tmp
write notes hello from ram
read NOTES.TXT
Prompt Format¶
The prompt is assembled by config::get_prompt() from SYSTEM_CONFIG:
user@host:path >
Example: root@rourex:/ > or root@rourex:/mnt/fat/GFX >.
Falls back to $ if the config lock is contended.
ELF Execution¶
bg and fg both delegate to input::elf::run_elf(filename, args, mode):
- Asks the scheduler which slot the program will occupy (
next_free_slot); fails withno free process slotwhen all 32 are held by live processes (including kernel tasks). - Finds the ELF file: an absolute path selects it directly; a bare name searches
/mnt/tmp/jug, the working directory,/mnt/tar/bin, then/mnt/iso/bin. Stages it in a temporary user-heap buffer. - Copies the
PT_LOADsegments into the slot's private 2 MiB physical frame and builds a page table that maps it at0x600_000. - Pushes the argv frame onto the slot's initial user stack and creates the scheduler task at the ELF entry point.
Foreground: the launcher (the shell, orinit_rc) is recorded as the child's waiter and parked until the child ends.Background: returns immediately; the shell stays interactive.
Userland processes communicate with the kernel via interrupt 0x7F (syscall gate). See Syscall specification for the full syscall interface, and the SDK for building programs.
Related documentation: Build and Run, Application Suite, Keyboard, Scheduler.