Files
nt-lite/code/user/apps/shell_native/shell_native.c
T
maksw 73abd6f90d isolate POSIX builds from the host UCRT, wire lwext4 and ntfs-3g as ext4.sys and ntfs.sys, split the FAT driver into directory/file/async/driver/mount units, add posixsrv and dwm plus input/console/desktop syscall clients and a pile of new smoke targets, rename serial.sys to cereal.sys, name HDA/USB/lwIP/AHCI workers, harden ATA probing/reset/removal around actual hardware deadlines, absent-channel detection, diagnostics and explicit worker lifetime, redo ACPI S5 shutdown around GAS/MMIO and HW-reduced firmware, scan SSDTs for _S5 and deal with Intel SMI sleep trapping, make serial and SMP timeouts use real monotonic deadlines, add thread names and fix terminal thread teardown, scheduler and APC prepare/commit races, make advisory file locks queryable and preserve split ranges and add mutable file append state, add shared-memory pipes with kernel-assisted wait/wake, introduce capability-scoped input and display managers, split surface map rights into read/write, add explicit unmap and replace present with commit/generation/damage tracking while keeping physical presentation under the display manager, decouple native exception classes from Win32 exception numbers and translate them in kernel32, add opaque process startup data, bump the resource protocol to v3 with namespace directories, symlinks and enumeration and service control to v2 with generic READY handle exports, add the new POSIX errno/status surface and rebuild fds around posixsrv-owned shared open descriptions, descriptor-local flags, exact inheritance snapshots, dup/fcntl/record locks and shared-ring pipes, add waitpid, POSIX credentials/groups/sessions/passwd/group lookups and move sockets onto stable open descriptions, port the shells and apps to the new console/input services and surface commit API, teach init to load services.ini and start/supervise RSSRV, DWM and generic services under restricted capabilities while publishing their endpoints through RSSRV, split RSSRV into namespace, volume, display, session, input, console and resource components and make /SystemRoot a real symlink to the independently published system volume, shift the syscall table again, expand lock/resource/surface/POSIX/service/thread smoke coverage, make docs scream ASK QUESTIONS and DISCUSS at LLMs, replace MIT No Attribution with WTFPL+.
2026-09-16 10:33:20 +02:00

2290 lines
88 KiB
C

// User application entry points for shell_native.
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <ntlite/syscall.h>
#include <ntlite/input_service.h>
#include <ntlite/console_service.h>
#include <ntlite/process_loader.h>
#include <ntlite/path.h>
#include <ntlite/resource.h>
#include <ntlite/status.h>
#define MAX_CMD 256
#define SHELL_FOREGROUND_POLL_MS 30u
#define MAX_PROCS 64 // Maximum number of processes we will fetch at once
#define MAX_THREADS 128
#define SHELL_PROMPT "> "
#define SHELL_GLYPH_WIDTH 8
#define SHELL_GLYPH_HEIGHT 16
#define SHELL_TEXT_FOREGROUND 0x00CCCCCCu
#define SHELL_TEXT_BACKGROUND 0x00012456u
#define SHELL_CURSOR_FOREGROUND 0x00000000u
#define SHELL_CURSOR_BACKGROUND 0x00E0E0E0u
// Output helpers.
static void print(const char* s) { (void)NtlConsoleWrite(SYS_HANDLE_INVALID, s, strlen(s), 0); }
// Opens file.
static uint32_t open_file(const char* path, uint32_t* handleOut) {
return NtlOpenFile(SysSvFromCstr(path), SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_QUERY,
SYS_FILE_OPEN_EXISTING, SYS_FILE_FLAG_NONE, handleOut);
}
// Creates file.
static uint32_t create_file(const char* path, uint32_t* handleOut) {
return NtlOpenFile(SysSvFromCstr(path), SYS_FILE_ACCESS_WRITE | SYS_FILE_ACCESS_QUERY,
SYS_FILE_CREATE_ALWAYS, SYS_FILE_FLAG_NONE, handleOut);
}
// Opens dir.
static uint32_t open_dir(const char* path, uint32_t* handleOut) {
return NtlOpenDir(SysSvFromCstr(path), SYS_DIR_ACCESS_ENUMERATE | SYS_DIR_ACCESS_OPEN,
SYS_DIR_FLAG_NONE, handleOut);
}
// Updates cwd.
static uint32_t set_cwd(const char* path) {
return NtlSetCurrentDirectory(SysSvFromCstr(path));
}
// Releases file.
static uint32_t delete_file(const char* path) {
return NtlDeleteFile(SysSvFromCstr(path));
}
// Creates process.
static uint32_t create_process(const char* path, uint32_t* handleOut, const char* cmdline) {
uint32_t imageFile = SYS_HANDLE_INVALID;
uint32_t status = open_file(path, &imageFile);
if (status != NTLSTATUS_SUCCESS) return status;
NTL_CREATE_SYSTEM_PROCESS_REQUEST req;
memset(&req, 0, sizeof(req));
req.Size = sizeof(req);
req.Flags = NTL_PROCESS_LOAD_FLAG_NONE;
req.ImageFile = imageFile;
req.Path = SysSvFromCstr(path);
req.CommandLine = SysSvFromCstr(cmdline);
req.SecurityContext = SYS_SECURITY_CONTEXT_CURRENT;
req.ResolveModuleName = NtlResolveSystemModuleName;
req.ProcessHandleOut = handleOut;
status = NtlCreateSystemProcess(&req);
(void)SysCloseHandle(imageFile);
return status;
}
// Prints u Int.
static void printUInt(uint32_t n) {
char buf[12]; int i = 0;
if (n == 0) { print("0"); return; }
while (n > 0) { buf[i++] = (char)('0' + n % 10); n /= 10; }
while (i > 0) { char c[2] = { buf[--i], '\0' }; print(c); }
}
// Prints int.
static void printInt(int32_t n) {
if (n < 0) { print("-"); printUInt((uint32_t)-(n + 1) + 1); }
else { printUInt((uint32_t)n); }
}
// Parses an unsigned decimal integer.
static bool parseUInt(const char* text, uint32_t* out) {
if (!text || !out) return false;
while (*text == ' ' || *text == '\t') text++;
if (*text < '0' || *text > '9') return false;
uint32_t value = 0;
while (*text >= '0' && *text <= '9') {
uint32_t digit = (uint32_t)(*text - '0');
if (value > (0xffffffffu - digit) / 10u) return false;
value = value * 10u + digit;
text++;
}
while (*text == ' ' || *text == '\t') text++;
if (*text != '\0') return false;
*out = value;
return true;
}
// Prints u Int64.
static void printUInt64(uint64_t n) {
if (n == 0) { print("0"); return; }
char buf[20]; int i = 0;
while (n > 0) { buf[i++] = (char)('0' + (int)(n % 10)); n /= 10; }
while (i > 0) { char c[2] = { buf[--i], '\0' }; print(c); }
}
// Implements the u64 Digits operation.
static uint32_t u64Digits(uint64_t n) {
uint32_t digits = 1;
while (n >= 10u) { n /= 10u; digits++; }
return digits;
}
// Prints spaces.
static void printSpaces(size_t count) {
while (count--) print(" ");
}
// Prints u Int Width.
static void printUIntWidth(uint32_t n, size_t width) {
uint32_t digits = u64Digits(n);
if (width > digits) printSpaces(width - digits);
printUInt(n);
}
// Prints u Int Zero Width.
static void printUIntZeroWidth(uint32_t n, size_t width) {
uint32_t digits = u64Digits(n);
while (width > digits) { print("0"); width--; }
printUInt(n);
}
// Prints u Int64 Width.
static void printUInt64Width(uint64_t n, size_t width) {
uint32_t digits = u64Digits(n);
if (width > digits) printSpaces(width - digits);
printUInt64(n);
}
// Names nt-lite process-abort exit statuses.
static const char* processExitStatusName(uint32_t code) {
switch (code) {
case NTLSTATUS_PROCESS_KILLED: return "killed";
case NTLSTATUS_PROCESS_PAGE_FAULT: return "page-fault";
case NTLSTATUS_PROCESS_GENERAL_PROTECTION: return "general-protection";
case NTLSTATUS_PROCESS_ILLEGAL_OPCODE: return "illegal-opcode";
case NTLSTATUS_PROCESS_DIVIDE_BY_ZERO: return "divide-by-zero";
case NTLSTATUS_PROCESS_BREAKPOINT: return "breakpoint";
case NTLSTATUS_PROCESS_ALIGNMENT_FAULT: return "alignment-fault";
case NTLSTATUS_PROCESS_UNKNOWN_FAULT: return "unknown-fault";
default: return NULL;
}
}
// Prints hex32.
static void printHex32(uint32_t v) {
static const char hex[] = "0123456789abcdef";
char buf[9];
for (int i = 7; i >= 0; i--) {
buf[i] = hex[v & 0xFu];
v >>= 4;
}
buf[8] = '\0';
print(buf);
}
// Prints dir Time.
static void printDirTime(const SYS_SYSTEM_TIME* t) {
if (!t || !(t->Flags & SYS_TIME_FLAG_VALID)) {
print("---- -- -- --:-- ");
return;
}
printUIntZeroWidth(t->Year, 4);
print("-");
printUIntZeroWidth(t->Month, 2);
print("-");
printUIntZeroWidth(t->Day, 2);
print(" ");
printUIntZeroWidth(t->Hour, 2);
print(":");
printUIntZeroWidth(t->Minute, 2);
print(" ");
}
// Prints string Width.
static void printStringWidth(const char* s, size_t width) {
size_t len = s ? strlen(s) : 0;
if (s) print(s);
if (width > len) printSpaces(width - len);
}
#define SHELL_HISTORY_DEPTH 16
static char gHistory[SHELL_HISTORY_DEPTH][MAX_CMD];
static size_t gHistoryCount;
typedef struct SHELL_EDITOR {
char* Buffer;
int Capacity;
int Length;
int Cursor;
} SHELL_EDITOR;
typedef struct SHELL_VISIBLE_CURSOR {
int Column;
int Row;
char Character;
bool Visible;
} SHELL_VISIBLE_CURSOR;
static const char* const gShellBuiltinCommands[] = {
"cd",
"clear",
"crash",
"date",
"del",
"dir",
"display",
"exit",
"surfbench",
"gpu",
"help",
"kill",
"mem",
"ps",
"stats",
"telemetry",
"threads",
"time",
"type",
"volume",
"write",
};
// Converts a key event into the shell's printable character model.
static char shellKeyToChar(INPUT_KEY key, uint32_t modifiers) {
bool shifted = (modifiers & INPUT_MOD_SHIFT) != 0;
bool caps = (modifiers & INPUT_MOD_CAPS_LOCK) != 0;
if (key >= INPUT_KEY_A && key <= INPUT_KEY_Z) {
char c = (char)('a' + (key - INPUT_KEY_A));
if (shifted ^ caps) c = (char)(c - 'a' + 'A');
return c;
}
if (key >= INPUT_KEY_1 && key <= INPUT_KEY_9) {
static const char shiftedDigits[] = "!@#$%^&*(";
char normal = (char)('1' + (key - INPUT_KEY_1));
return shifted ? shiftedDigits[key - INPUT_KEY_1] : normal;
}
switch (key) {
case INPUT_KEY_0: return shifted ? ')' : '0';
case INPUT_KEY_MINUS: return shifted ? '_' : '-';
case INPUT_KEY_EQUAL: return shifted ? '+' : '=';
case INPUT_KEY_LEFT_BRACKET: return shifted ? '{' : '[';
case INPUT_KEY_RIGHT_BRACKET: return shifted ? '}' : ']';
case INPUT_KEY_BACKSLASH: return shifted ? '|' : '\\';
case INPUT_KEY_SEMICOLON: return shifted ? ':' : ';';
case INPUT_KEY_APOSTROPHE: return shifted ? '"' : '\'';
case INPUT_KEY_GRAVE: return shifted ? '~' : '`';
case INPUT_KEY_COMMA: return shifted ? '<' : ',';
case INPUT_KEY_PERIOD: return shifted ? '>' : '.';
case INPUT_KEY_SLASH: return shifted ? '?' : '/';
case INPUT_KEY_SPACE: return ' ';
case INPUT_KEY_TAB: return '\t';
case INPUT_KEY_KP_DIVIDE: return '/';
case INPUT_KEY_KP_MULTIPLY: return '*';
case INPUT_KEY_KP_MINUS: return '-';
case INPUT_KEY_KP_PLUS: return '+';
case INPUT_KEY_KP_0: return '0';
case INPUT_KEY_KP_1: return '1';
case INPUT_KEY_KP_2: return '2';
case INPUT_KEY_KP_3: return '3';
case INPUT_KEY_KP_4: return '4';
case INPUT_KEY_KP_5: return '5';
case INPUT_KEY_KP_6: return '6';
case INPUT_KEY_KP_7: return '7';
case INPUT_KEY_KP_8: return '8';
case INPUT_KEY_KP_9: return '9';
case INPUT_KEY_KP_PERIOD: return '.';
default: return 0;
}
}
// Adds a non-empty command to the in-memory history ring.
static void shellHistoryAdd(const char* cmd) {
if (!cmd || !*cmd) return;
if (gHistoryCount > 0 && strcmp(gHistory[gHistoryCount - 1], cmd) == 0) return;
if (gHistoryCount == SHELL_HISTORY_DEPTH) {
memmove(gHistory[0], gHistory[1], (SHELL_HISTORY_DEPTH - 1) * MAX_CMD);
gHistoryCount--;
}
strncpy(gHistory[gHistoryCount], cmd, MAX_CMD - 1);
gHistory[gHistoryCount][MAX_CMD - 1] = '\0';
gHistoryCount++;
}
// Restores the character underneath the visible edit cursor.
static void shellEditorHideVisibleCursor(SHELL_VISIBLE_CURSOR* cursor) {
if (!cursor || !cursor->Visible) return;
(void)NtlConsolePutCharacter(SYS_HANDLE_INVALID, cursor->Character,
cursor->Column * SHELL_GLYPH_WIDTH,
cursor->Row * SHELL_GLYPH_HEIGHT,
SHELL_TEXT_FOREGROUND, SHELL_TEXT_BACKGROUND);
cursor->Visible = false;
}
// Draws the same steady block cursor used by edit without changing console state.
static void shellEditorShowVisibleCursor(SHELL_VISIBLE_CURSOR* cursor, const SHELL_EDITOR* editor) {
if (!cursor || !editor) return;
shellEditorHideVisibleCursor(cursor);
NTL_CONSOLE_INFO info;
if (NtlConsoleQueryInfo(SYS_HANDLE_INVALID, &info) != NTLSTATUS_SUCCESS) return;
char character = editor->Cursor < editor->Length
? editor->Buffer[editor->Cursor]
: ' ';
if (NtlConsolePutCharacter(SYS_HANDLE_INVALID, character,
(int)info.CursorX * SHELL_GLYPH_WIDTH,
(int)info.CursorY * SHELL_GLYPH_HEIGHT,
SHELL_CURSOR_FOREGROUND, SHELL_CURSOR_BACKGROUND) != NTLSTATUS_SUCCESS)
return;
cursor->Column = (int)info.CursorX;
cursor->Row = (int)info.CursorY;
cursor->Character = character;
cursor->Visible = true;
}
// Moves the visible cursor left by the requested number of cells.
static void shellEditorMoveLeftCells(int count) {
while (count-- > 0) print("\b");
}
// Moves the editor cursor without changing the buffer.
static void shellEditorMoveCursor(SHELL_EDITOR* editor, int target) {
if (!editor) return;
if (target < 0) target = 0;
if (target > editor->Length) target = editor->Length;
if (target < editor->Cursor) {
shellEditorMoveLeftCells(editor->Cursor - target);
} else {
while (editor->Cursor < target) {
char echo[2] = { editor->Buffer[editor->Cursor], '\0' };
print(echo);
editor->Cursor++;
}
}
editor->Cursor = target;
}
// Redraws the changed tail and restores the requested cursor position.
static void shellEditorRedrawTail(SHELL_EDITOR* editor, int start, int oldLength, int targetCursor) {
if (!editor) return;
print(editor->Buffer + start);
if (oldLength > editor->Length) printSpaces((size_t)(oldLength - editor->Length));
int displayedEnd = oldLength > editor->Length ? oldLength : editor->Length;
shellEditorMoveLeftCells(displayedEnd - targetCursor);
editor->Cursor = targetCursor;
}
// Replaces one buffer range and keeps the visible line synchronized.
static bool shellEditorReplaceRange(SHELL_EDITOR* editor, int start, int end, const char* text) {
if (!editor || !editor->Buffer || editor->Capacity <= 0 || !text) return false;
if (start < 0 || end < start || end > editor->Length) return false;
shellEditorMoveCursor(editor, start);
int oldLength = editor->Length;
int removed = end - start;
int available = editor->Capacity - 1 - (oldLength - removed);
int replacementLength = 0;
while (text[replacementLength] && replacementLength < available) replacementLength++;
memmove(editor->Buffer + start + replacementLength,
editor->Buffer + end,
(size_t)(oldLength - end + 1));
if (replacementLength > 0)
memcpy(editor->Buffer + start, text, (size_t)replacementLength);
editor->Length = oldLength - removed + replacementLength;
int targetCursor = start + replacementLength;
shellEditorRedrawTail(editor, start, oldLength, targetCursor);
return removed != replacementLength || replacementLength != 0;
}
// Inserts text at the current cursor position.
static bool shellEditorInsert(SHELL_EDITOR* editor, const char* text) {
if (!editor) return false;
return shellEditorReplaceRange(editor, editor->Cursor, editor->Cursor, text);
}
// Replaces the complete visible line and leaves the cursor at its end.
static void shellEditorReplaceLine(SHELL_EDITOR* editor, const char* text) {
if (!editor) return;
(void)shellEditorReplaceRange(editor, 0, editor->Length, text ? text : "");
}
// Returns true when a character separates shell tokens.
static bool shellIsTokenSeparator(char c) {
return c == ' ' || c == '\t';
}
// Returns true when a character separates path components.
static bool shellIsPathSeparator(char c) {
return c == '/' || c == '\\';
}
// Returns true when the token already names an explicit path.
static bool shellTokenHasPathSeparator(const char* token, size_t length) {
for (size_t i = 0; i < length; i++) {
if (shellIsPathSeparator(token[i])) return true;
}
return false;
}
// Returns an ASCII lower-case value for case-insensitive shell name handling.
static char shellAsciiLower(char c) {
if (c >= 'A' && c <= 'Z')
return (char)(c - 'A' + 'a');
return c;
}
// Returns true when name starts with prefix without treating ASCII case as significant.
static bool shellNameStartsWith(const char* name, const char* prefix, size_t prefixLength) {
if (!name || !prefix) return false;
for (size_t i = 0; i < prefixLength; i++) {
if (name[i] == '\0' || shellAsciiLower(name[i]) != shellAsciiLower(prefix[i])) return false;
}
return true;
}
// Extends an in-progress common prefix case-insensitively while preserving the first candidate's spelling.
static void shellUpdateCommonPrefix(char* common, size_t commonSize, const char* name, uint32_t matchCount) {
if (!common || commonSize == 0 || !name) return;
if (matchCount == 0) {
strncpy(common, name, commonSize - 1);
common[commonSize - 1] = '\0';
return;
}
size_t i = 0;
while (common[i] && name[i] && shellAsciiLower(common[i]) == shellAsciiLower(name[i])) i++;
common[i] = '\0';
}
// Prints one completion candidate.
static void shellPrintCompletionCandidate(const char* name, bool directory) {
print(" ");
print(name);
if (directory) print("/");
print("\n");
}
// Tracks completion candidates without storing the full candidate list.
typedef struct SHELL_COMPLETION_STATE {
uint32_t MatchCount;
bool LastIsDirectory;
bool LastAddsSpace;
char Common[SYS_DIR_NAME_MAX];
} SHELL_COMPLETION_STATE;
// Records one completion candidate.
static void shellRecordCompletion(SHELL_COMPLETION_STATE* state, const char* name, bool directory, bool addsSpace) {
if (!state || !name || !*name) return;
shellUpdateCommonPrefix(state->Common, sizeof(state->Common), name, state->MatchCount);
state->MatchCount++;
state->LastIsDirectory = directory;
state->LastAddsSpace = addsSpace;
}
// Collects builtin command matches for a command-position token.
static void shellCollectBuiltinCompletions(const char* prefix, size_t prefixLength,
SHELL_COMPLETION_STATE* state,
bool printMatches) {
size_t count = sizeof(gShellBuiltinCommands) / sizeof(gShellBuiltinCommands[0]);
for (size_t i = 0; i < count; i++) {
const char* name = gShellBuiltinCommands[i];
if (!shellNameStartsWith(name, prefix, prefixLength)) continue;
if (printMatches) shellPrintCompletionCandidate(name, false);
else shellRecordCompletion(state, name, false, true);
}
}
// Splits a token into a directory to scan and a filename prefix to match.
static bool shellSplitCompletionPath(const char* token, size_t tokenLength,
char* dir, size_t dirSize,
const char** prefixOut, size_t* prefixLengthOut) {
if (!token || !dir || dirSize == 0 || !prefixOut || !prefixLengthOut) return false;
size_t lastSeparator = (size_t)-1;
for (size_t i = 0; i < tokenLength; i++) {
if (shellIsPathSeparator(token[i])) lastSeparator = i;
}
if (lastSeparator == (size_t)-1) {
if (dirSize < 2) return false;
dir[0] = '.';
dir[1] = '\0';
*prefixOut = token;
*prefixLengthOut = tokenLength;
return true;
}
size_t dirLength = lastSeparator;
if (lastSeparator == 0) dirLength = 1;
if (lastSeparator >= 2 && token[1] == ':' && shellIsPathSeparator(token[2])) dirLength = lastSeparator + 1;
if (dirLength + 1 > dirSize) return false;
memcpy(dir, token, dirLength);
dir[dirLength] = '\0';
*prefixOut = token + lastSeparator + 1;
*prefixLengthOut = tokenLength - lastSeparator - 1;
return true;
}
// Collects immediate RSSRV namespace children when the completion directory is a namespace directory.
static void shellCollectResourceCompletions(const char* token, size_t tokenLength,
SHELL_COMPLETION_STATE* state,
bool printMatches) {
char dir[MAX_CMD];
const char* prefix = token;
size_t prefixLength = tokenLength;
if (!shellSplitCompletionPath(token, tokenLength, dir, sizeof(dir), &prefix, &prefixLength)) return;
if (dir[0] != '/') return;
SYS_HANDLE session = SYS_HANDLE_INVALID;
if (!KSUCCESS(NtlResourceConnect(&session))) return;
uint32_t kind = NTL_RESOURCE_KIND_INVALID;
KSTATUS status = NtlResourceQuery(session, SysSvFromCstr(dir), &kind);
if (!KSUCCESS(status) || kind != NTL_RESOURCE_KIND_NAMESPACE_DIRECTORY) {
(void)NtlResourceClose(session);
return;
}
NTL_RESOURCE_ENUM_CURSOR cursor;
memset(&cursor, 0, sizeof(cursor));
for (;;) {
NTL_RESOURCE_ENUM_ENTRY entry;
status = NtlResourceEnumerate(session, SysSvFromCstr(dir), &cursor, &entry);
if (status == NTLSTATUS_NO_MORE_FILES) break;
if (!KSUCCESS(status)) break;
if (!shellNameStartsWith(entry.Name, prefix, prefixLength)) continue;
bool directory = entry.Kind == NTL_RESOURCE_KIND_NAMESPACE_DIRECTORY ||
entry.Kind == NTL_RESOURCE_KIND_SYMBOLIC_LINK;
if (printMatches) shellPrintCompletionCandidate(entry.Name, directory);
else shellRecordCompletion(state, entry.Name, directory, true);
}
(void)NtlResourceClose(session);
}
// Collects filesystem path matches using the existing directory enumeration ABI.
static void shellCollectPathCompletions(const char* token, size_t tokenLength,
SHELL_COMPLETION_STATE* state,
bool printMatches) {
char dir[MAX_CMD];
const char* prefix = token;
size_t prefixLength = tokenLength;
if (!shellSplitCompletionPath(token, tokenLength, dir, sizeof(dir), &prefix, &prefixLength)) return;
uint32_t hDir = 0;
if (open_dir(dir, &hDir) != 0) return;
SYS_DIR_ENTRY entry;
while (SysReadDir(hDir, &entry) == 0) {
if (!entry.Name[0]) continue;
if (!shellNameStartsWith(entry.Name, prefix, prefixLength)) continue;
bool directory = (entry.Attr & 0x10u) != 0;
if (printMatches) shellPrintCompletionCandidate(entry.Name, directory);
else shellRecordCompletion(state, entry.Name, directory, true);
}
SysCloseHandle(hDir);
}
// Redraws the prompt and current edit buffer after a completion list.
static void shellRedrawPromptAndLine(SHELL_EDITOR* editor) {
print(SHELL_PROMPT);
if (!editor) return;
print(editor->Buffer);
shellEditorMoveLeftCells(editor->Length - editor->Cursor);
}
// Completes the token around the current cursor position.
static void shellCompleteLine(SHELL_EDITOR* editor) {
if (!editor || !editor->Buffer || editor->Capacity <= 0 || editor->Cursor < 0) return;
char* buf = editor->Buffer;
size_t cursor = (size_t)editor->Cursor;
size_t tokenStart = cursor;
while (tokenStart > 0 && !shellIsTokenSeparator(buf[tokenStart - 1])) tokenStart--;
size_t tokenEnd = cursor;
while (tokenEnd < (size_t)editor->Length && !shellIsTokenSeparator(buf[tokenEnd])) tokenEnd++;
const char* token = buf + tokenStart;
size_t tokenLength = cursor - tokenStart;
bool commandPosition = tokenStart == 0;
bool explicitPath = shellTokenHasPathSeparator(token, tokenLength);
char completionDir[MAX_CMD];
const char* namePrefix = token;
size_t namePrefixLength = tokenLength;
(void)shellSplitCompletionPath(token, tokenLength, completionDir, sizeof(completionDir), &namePrefix, &namePrefixLength);
SHELL_COMPLETION_STATE state;
memset(&state, 0, sizeof(state));
if (commandPosition && !explicitPath) {
shellCollectBuiltinCompletions(token, tokenLength, &state, false);
}
shellCollectResourceCompletions(token, tokenLength, &state, false);
shellCollectPathCompletions(token, tokenLength, &state, false);
if (state.MatchCount == 0) return;
size_t commonLength = strlen(state.Common);
bool expanded = commonLength > namePrefixLength;
bool canonicalized = commonLength == namePrefixLength &&
memcmp(state.Common, namePrefix, namePrefixLength) != 0;
if (expanded || canonicalized) {
size_t nameStart = tokenStart + (size_t)(namePrefix - token);
(void)shellEditorReplaceRange(editor, (int)nameStart, (int)tokenEnd, state.Common);
}
if (state.MatchCount == 1) {
if (state.LastIsDirectory) {
if (editor->Cursor < editor->Capacity - 1 && editor->Cursor > 0 &&
!shellIsPathSeparator(buf[editor->Cursor - 1]))
(void)shellEditorInsert(editor, "/");
} else if (state.LastAddsSpace) {
if (editor->Cursor < editor->Capacity - 1 &&
(editor->Cursor == editor->Length ||
!shellIsTokenSeparator(buf[editor->Cursor])))
(void)shellEditorInsert(editor, " ");
}
return;
}
if (expanded) return;
print("\n");
if (commandPosition && !explicitPath) {
shellCollectBuiltinCompletions(token, tokenLength, NULL, true);
}
shellCollectResourceCompletions(token, tokenLength, NULL, true);
shellCollectPathCompletions(token, tokenLength, NULL, true);
shellRedrawPromptAndLine(editor);
}
// Reads one editable command line from the keyboard.
static bool readLine(char* buf, int len) {
SHELL_EDITOR editor;
SHELL_VISIBLE_CURSOR visibleCursor;
char historyDraft[MAX_CMD];
size_t historyCursor = gHistoryCount;
if (len <= 0) return false;
editor.Buffer = buf;
editor.Capacity = len;
editor.Length = 0;
editor.Cursor = 0;
memset(&visibleCursor, 0, sizeof(visibleCursor));
buf[0] = '\0';
historyDraft[0] = '\0';
while (true) {
shellEditorShowVisibleCursor(&visibleCursor, &editor);
INPUT_KEY_RECORD input;
KSTATUS inputStatus = NtlInputReadEvent(SYS_HANDLE_INVALID, SYS_WAIT_TIMEOUT_INFINITE, &input);
shellEditorHideVisibleCursor(&visibleCursor);
if (inputStatus != NTLSTATUS_SUCCESS) { SysYield(); continue; }
INPUT_KEY key = input.Key;
if (key == INPUT_KEY_NONE) { SysYield(); continue; }
uint32_t modifiers = input.Modifiers;
if ((modifiers & INPUT_MOD_CTRL) && key == INPUT_KEY_C) {
buf[0] = '\0';
print("^C\n");
return true;
}
if (key == INPUT_KEY_ENTER || key == INPUT_KEY_KP_ENTER) {
print("\n");
break;
}
if (key == INPUT_KEY_BACKSPACE) {
if (editor.Cursor > 0)
(void)shellEditorReplaceRange(&editor, editor.Cursor - 1, editor.Cursor, "");
continue;
}
if (key == INPUT_KEY_DELETE) {
if (editor.Cursor < editor.Length)
(void)shellEditorReplaceRange(&editor, editor.Cursor, editor.Cursor + 1, "");
continue;
}
if (key == INPUT_KEY_LEFT) {
shellEditorMoveCursor(&editor, editor.Cursor - 1);
continue;
}
if (key == INPUT_KEY_RIGHT) {
shellEditorMoveCursor(&editor, editor.Cursor + 1);
continue;
}
if (key == INPUT_KEY_HOME) {
shellEditorMoveCursor(&editor, 0);
continue;
}
if (key == INPUT_KEY_END) {
shellEditorMoveCursor(&editor, editor.Length);
continue;
}
if (key == INPUT_KEY_UP) {
if (historyCursor > 0) {
if (historyCursor == gHistoryCount) {
strncpy(historyDraft, editor.Buffer, sizeof(historyDraft) - 1);
historyDraft[sizeof(historyDraft) - 1] = '\0';
}
historyCursor--;
shellEditorReplaceLine(&editor, gHistory[historyCursor]);
}
continue;
}
if (key == INPUT_KEY_DOWN) {
if (historyCursor < gHistoryCount) {
historyCursor++;
shellEditorReplaceLine(&editor,
historyCursor < gHistoryCount ? gHistory[historyCursor] : historyDraft);
}
continue;
}
if (key == INPUT_KEY_TAB) {
shellCompleteLine(&editor);
continue;
}
char c = input.Char ? input.Char : shellKeyToChar(key, modifiers);
if (c < 0x20 || c == 127) continue;
char text[2] = { c, '\0' };
(void)shellEditorInsert(&editor, text);
}
return false;
}
// Implements the trim operation.
static char* trim(char* s) {
while (*s == ' ') s++;
int len = (int)strlen(s);
while (len > 0 && s[len - 1] == ' ') len--;
s[len] = '\0';
return s;
}
// Built-in commands.
static void cmd_help() {
print("Available commands:\n"
" help - Show this list\n"
" mem - Show memory usage\n"
" time - Show system wall-clock time\n"
" display - Show display provider and counters\n"
" surfbench - Benchmark Doom-size and full-screen surface commits\n"
" stats - Show scheduler/CPU/MM telemetry\n"
" ps - List processes\n"
" threads <pid> - Show one process's thread statuses\n"
" kill <pid> - Terminate a process\n"
" dir [path] - List directory contents\n"
" cd <path> - Change directory\n"
" type <file> - Display file contents\n"
" volume [0-100] - Query or set master audio volume\n"
" volume mute - Mute the default audio endpoint\n"
" volume unmute - Unmute the default audio endpoint\n"
" del <file> - Delete a file\n"
" write <file> <tx> - Create a file with text\n"
" clear - Clear the screen\n"
" exit - Close the shell\n");
}
// Prints size Ki B.
static void printSizeKiB(uint64_t bytes) {
printUInt64(bytes / 1024u);
print(" KiB");
}
// Prints pages Ki B.
static void printPagesKiB(uint64_t pages) {
printUInt64(pages * 4u);
print(" KiB");
}
// Prints cpu Flags.
static void printCpuFlags(uint32_t flags) {
if (flags & SYS_CPU_FLAG_BOOT_PROCESSOR) print("boot ");
if (flags & SYS_CPU_FLAG_ONLINE) print("online ");
if (flags & SYS_CPU_FLAG_PARKED) print("parked ");
if (flags & SYS_CPU_FLAG_PRIMARY) print("primary ");
if (flags & SYS_CPU_FLAG_STARTED) print("started ");
if (flags & SYS_CPU_FLAG_PRESENT) print("present ");
}
// Selects the available default audio endpoint, or the first available endpoint.
static bool shellQueryDefaultAudioEndpoint(SYS_AUDIO_ENDPOINT_INFO* endpointOut) {
if (!endpointOut) return false;
SYS_AUDIO_ENDPOINT_INFO endpoints[SYS_AUDIO_MAX_ENDPOINTS];
uint32_t count = 0;
SYS_AUDIO_ENUMERATE_ENDPOINTS_REQUEST request;
memset(&request, 0, sizeof(request));
request.Size = sizeof(request);
request.Endpoints = endpoints;
request.Capacity = SYS_AUDIO_MAX_ENDPOINTS;
request.CountOut = &count;
KSTATUS status = SysAudioEnumerateEndpoints(&request);
if (status != NTLSTATUS_SUCCESS && status != NTLSTATUS_BUFFER_TOO_SMALL) {
print("volume: endpoint query failed status=");
printUInt(status);
print("\n");
return false;
}
const SYS_AUDIO_ENDPOINT_INFO* fallback = NULL;
uint32_t availableCount = count < SYS_AUDIO_MAX_ENDPOINTS
? count
: SYS_AUDIO_MAX_ENDPOINTS;
for (uint32_t index = 0; index < availableCount; index++) {
const SYS_AUDIO_ENDPOINT_INFO* endpoint = &endpoints[index];
if (endpoint->Size != sizeof(*endpoint) ||
endpoint->Version != SYS_AUDIO_ABI_VERSION ||
endpoint->State != SysAudioEndpointReady ||
(endpoint->Flags & SYS_AUDIO_ENDPOINT_FLAG_AVAILABLE) == 0)
continue;
if (!fallback) fallback = endpoint;
if (endpoint->Flags & SYS_AUDIO_ENDPOINT_FLAG_DEFAULT) {
*endpointOut = *endpoint;
return true;
}
}
if (fallback) {
*endpointOut = *fallback;
return true;
}
print("volume: no available audio endpoint\n");
return false;
}
// Converts one public Q16 gain into a rounded percentage.
static uint32_t shellAudioVolumePercent(uint32_t volumeQ16) {
uint64_t scaled = (uint64_t)volumeQ16 * 100u + SYS_AUDIO_GAIN_Q16_UNITY / 2u;
return (uint32_t)(scaled / SYS_AUDIO_GAIN_Q16_UNITY);
}
// Converts one percentage into public Q16 gain.
static uint32_t shellAudioVolumeQ16(uint32_t percent) {
return (uint32_t)(((uint64_t)percent * SYS_AUDIO_GAIN_Q16_UNITY + 50u) / 100u);
}
// Queries or updates the default endpoint master volume.
static void cmd_volume(const char* args) {
SYS_AUDIO_ENDPOINT_INFO endpoint;
if (!shellQueryDefaultAudioEndpoint(&endpoint)) return;
while (args && (*args == ' ' || *args == '\t')) args++;
if (!args || *args == '\0') {
print("Volume: ");
printUInt(shellAudioVolumePercent(endpoint.MasterVolumeQ16));
print("%");
if (endpoint.MasterMuted) print(" (muted)");
print("\n");
return;
}
uint32_t volumeQ16 = endpoint.MasterVolumeQ16;
uint32_t muted = endpoint.MasterMuted ? 1u : 0u;
if (strcmp(args, "mute") == 0) {
muted = 1u;
} else if (strcmp(args, "unmute") == 0) {
muted = 0u;
} else {
uint32_t percent = 0;
if (!parseUInt(args, &percent) || percent > 100u) {
print("Usage: volume [0-100|mute|unmute]\n");
return;
}
volumeQ16 = shellAudioVolumeQ16(percent);
muted = 0u;
}
SYS_AUDIO_SET_MASTER_VOLUME_REQUEST request;
memset(&request, 0, sizeof(request));
request.Size = sizeof(request);
request.EndpointId = endpoint.EndpointId;
request.Muted = muted;
request.VolumeQ16 = volumeQ16;
KSTATUS status = SysAudioSetMasterVolume(&request);
if (status != NTLSTATUS_SUCCESS) {
print("volume: update failed status=");
printUInt(status);
print("\n");
return;
}
print("Volume: ");
printUInt(shellAudioVolumePercent(volumeQ16));
print("%");
if (muted) print(" (muted)");
print("\n");
}
// Implements the cmd stats operation.
static void cmd_stats(void) {
SYS_SCHEDULER_STATS sched;
SYS_PMM_STATS pmm;
SYS_CPU_STATS* cpu = 0;
void* cpuBuffer = 0;
SYS_PFN_STATS pfn;
SYS_VAD_STATS vad;
SYS_SWAP_STATS swap;
SYS_FILE_CACHE_STATS fileCache;
SYS_FILESYSTEM_STATS filesystem;
SYS_DISK_STATS disk;
SYS_PTE_STATS pte;
SYS_SURFACE_STATS surface;
SYS_EXCEPTION_STATS exceptionStats;
uint32_t status;
status = SysQueryKernelStats(SYS_KERNEL_STATS_SCHEDULER, &sched, sizeof(sched), NULL);
if (status != 0) {
print("stats: scheduler query failed: ");
printUInt(status);
print("\n");
return;
}
status = SysQueryKernelStats(SYS_KERNEL_STATS_PMM, &pmm, sizeof(pmm), NULL);
if (status != 0) {
print("stats: pmm query failed: ");
printUInt(status);
print("\n");
return;
}
size_t cpuSize = 0;
status = SysQueryKernelStats(SYS_KERNEL_STATS_CPU, 0, 0, &cpuSize);
if (status != 0 || cpuSize < sizeof(SYS_CPU_STATS)) {
print("stats: cpu size query failed: ");
printUInt(status);
print("\n");
return;
}
size_t cpuPages = (cpuSize + 4095u) / 4096u;
if (cpuPages == 0) cpuPages = 1;
SYS_ALLOC_VM_REQUEST allocReq;
memset(&allocReq, 0, sizeof(allocReq));
allocReq.Size = sizeof(allocReq);
allocReq.PageCount = cpuPages;
allocReq.Protect = SYS_VM_READWRITE;
allocReq.Flags = SYS_VM_FLAG_NONE;
allocReq.BaseOut = &cpuBuffer;
status = SysAllocVm(&allocReq);
if (status != 0 || !cpuBuffer) {
print("stats: cpu buffer allocation failed: ");
printUInt(status);
print("\n");
return;
}
cpu = (SYS_CPU_STATS*)cpuBuffer;
status = SysQueryKernelStats(SYS_KERNEL_STATS_CPU, cpu, cpuPages * 4096u, NULL);
if (status != 0) {
print("stats: cpu query failed: ");
printUInt(status);
print("\n");
SysFreeVm(cpuBuffer);
return;
}
status = SysQueryKernelStats(SYS_KERNEL_STATS_PFN, &pfn, sizeof(pfn), NULL);
if (status != 0) {
print("stats: pfn query failed: ");
printUInt(status);
print("\n");
SysFreeVm(cpuBuffer);
return;
}
status = SysQueryKernelStats(SYS_KERNEL_STATS_VAD, &vad, sizeof(vad), NULL);
if (status != 0) {
print("stats: vad query failed: ");
printUInt(status);
print("\n");
SysFreeVm(cpuBuffer);
return;
}
status = SysQueryKernelStats(SYS_KERNEL_STATS_SWAP, &swap, sizeof(swap), NULL);
if (status != 0) {
print("stats: swap query failed: ");
printUInt(status);
print("\n");
SysFreeVm(cpuBuffer);
return;
}
status = SysQueryKernelStats(SYS_KERNEL_STATS_FILE_CACHE, &fileCache, sizeof(fileCache), NULL);
if (status != 0) {
print("stats: file cache query failed: ");
printUInt(status);
print("\n");
SysFreeVm(cpuBuffer);
return;
}
status = SysQueryKernelStats(SYS_KERNEL_STATS_FILESYSTEM, &filesystem, sizeof(filesystem), NULL);
if (status != 0) {
print("stats: filesystem query failed: ");
printUInt(status);
print("\n");
SysFreeVm(cpuBuffer);
return;
}
status = SysQueryKernelStats(SYS_KERNEL_STATS_DISK, &disk, sizeof(disk), NULL);
if (status != 0) {
print("stats: disk query failed: ");
printUInt(status);
print("\n");
SysFreeVm(cpuBuffer);
return;
}
status = SysQueryKernelStats(SYS_KERNEL_STATS_PTE, &pte, sizeof(pte), NULL);
if (status != 0) {
print("stats: pte query failed: ");
printUInt(status);
print("\n");
SysFreeVm(cpuBuffer);
return;
}
status = SysQueryKernelStats(SYS_KERNEL_STATS_SURFACE, &surface, sizeof(surface), NULL);
if (status != 0) {
print("stats: surface query failed: ");
printUInt(status);
print("\n");
SysFreeVm(cpuBuffer);
return;
}
status = SysQueryKernelStats(SYS_KERNEL_STATS_EXCEPTION, &exceptionStats, sizeof(exceptionStats), NULL);
if (status != 0) {
print("stats: exception query failed: ");
printUInt(status);
print("\n");
SysFreeVm(cpuBuffer);
return;
}
print("Scheduler:\n");
print(" ticks: "); printUInt64(sched.Ticks); print("\n");
print(" context switches: "); printUInt64(sched.ContextSwitches); print("\n");
print(" quantum expires: "); printUInt64(sched.QuantumExpirations); print("\n");
print(" priority preempts: "); printUInt64(sched.PriorityPreemptions); print("\n");
print(" idle selections: "); printUInt64(sched.IdleSelections); print("\n");
print(" keep-current: "); printUInt64(sched.KeepCurrentDecisions); print("\n");
print(" demotions: "); printUInt64(sched.Demotions); print("\n");
print(" aging promotions: "); printUInt64(sched.AgingPromotions); print("\n");
print(" voluntary blocks: "); printUInt64(sched.VoluntaryBlocks); print("\n");
print(" SMT deferrals: "); printUInt64(sched.SmtSiblingDeferrals); print("\n");
print(" SMT primary pokes: "); printUInt64(sched.SmtPrimaryPokes); print("\n");
print(" RT dispatches: "); printUInt64(sched.RealtimeDispatches); print("\n");
print(" RT preemptions: "); printUInt64(sched.RealtimePreemptions); print("\n");
print(" PI boosts: "); printUInt64(sched.PriorityInheritanceBoosts); print("\n");
print(" PI drops: "); printUInt64(sched.PriorityInheritanceDrops); print("\n");
print(" PI propagations: "); printUInt64(sched.PriorityInheritancePropagations); print("\n");
print(" PI max depth: "); printUInt64(sched.PriorityInheritanceMaxDepth); print("\n");
print("Exceptions:\n");
print(" delivered: "); printUInt64(exceptionStats.Delivered); print("\n");
print(" user-raised: "); printUInt64(exceptionStats.UserRaised); print("\n");
print(" continued: "); printUInt64(exceptionStats.Continued); print("\n");
print(" unhandled: "); printUInt64(exceptionStats.Unhandled); print("\n");
print(" invalid continue: "); printUInt64(exceptionStats.InvalidContinue); print("\n");
print(" max nesting: "); printUInt(exceptionStats.MaxNestedDispatch); print("\n");
print(" last code: "); printUInt(exceptionStats.LastCode); print("\n");
print("CPUs:\n");
const SYS_CPU_STAT* cpuRecords = SYS_CPU_STATS_CONST_RECORDS(cpu);
uint32_t n = cpu->RecordCount;
for (uint32_t i = 0; i < n; i++) {
const SYS_CPU_STAT* c = &cpuRecords[i];
print(" cpu"); printUInt(c->CpuIndex);
print(" hardware="); printUInt(c->HardwareId);
print(" current=");
if (c->CurrentThreadFlags & SYS_CPU_THREAD_FLAG_IDLE) {
print("idle/"); printUInt(c->CpuIndex);
} else {
print("tid/"); printUInt(c->CurrentTid);
}
print(" ticks="); printUInt64(c->SchedulerTicks);
print(" switches="); printUInt64(c->ContextSwitches);
print(" flags="); printCpuFlags(c->Flags);
print("\n");
}
print("Physical memory:\n");
print(" total: "); printPagesKiB(pmm.TotalFrames); print(" (frames="); printUInt64(pmm.TotalFrames); print(")\n");
print(" used: "); printPagesKiB(pmm.UsedFrames); print(" (frames="); printUInt64(pmm.UsedFrames); print(")\n");
print(" free: "); printPagesKiB(pmm.FreeFrames); print(" (frames="); printUInt64(pmm.FreeFrames); print(")\n");
print(" largest free run: "); printPagesKiB(pmm.LargestFreeRun); print(" (frames="); printUInt64(pmm.LargestFreeRun); print(")\n");
print(" free runs: "); printUInt64(pmm.FreeRunCount); print("\n");
print(" available+reclaim: "); printSizeKiB(pfn.AvailableFrames * 4096ull);
print(" (reclaimable="); printSizeKiB(pfn.ReclaimableFrames * 4096ull); print(")\n");
print(" run histogram:\n");
print(" 1: "); printUInt64(pmm.FreeRunHistogram[0]); print("\n");
print(" 2-3: "); printUInt64(pmm.FreeRunHistogram[1]); print("\n");
print(" 4-7: "); printUInt64(pmm.FreeRunHistogram[2]); print("\n");
print(" 8-15: "); printUInt64(pmm.FreeRunHistogram[3]); print("\n");
print(" 16-63: "); printUInt64(pmm.FreeRunHistogram[4]); print("\n");
print(" 64-255: "); printUInt64(pmm.FreeRunHistogram[5]); print("\n");
print(" 256-1023: "); printUInt64(pmm.FreeRunHistogram[6]); print("\n");
print(" 1024+: "); printUInt64(pmm.FreeRunHistogram[7]); print("\n");
print("PFN database:\n");
print(" states: active="); printUInt64(pfn.ActiveFrames);
print(" free="); printUInt64(pfn.FreeFrames);
print(" zeroed="); printUInt64(pfn.ZeroedFrames);
print(" standby="); printUInt64(pfn.StandbyFrames);
print(" modified="); printUInt64(pfn.ModifiedFrames);
print(" reserved="); printUInt64(pfn.ReservedFrames); print("\n");
print(" eviction: evictable="); printUInt64(pfn.EvictableFrames);
print(" reclaimable="); printUInt64(pfn.ReclaimableFrames);
print(" available="); printUInt64(pfn.AvailableFrames);
print(" mapped="); printUInt64(pfn.MappedFrames);
print(" non-evictable="); printUInt64(pfn.NonEvictableFrames);
print(" pinned="); printUInt64(pfn.PinnedFrames); print("\n");
print(" usage frames: kernel="); printUInt64(pfn.KernelFrames);
print(" pt="); printUInt64(pfn.PageTableFrames);
print(" user="); printUInt64(pfn.UserFrames);
print(" driver="); printUInt64(pfn.DriverFrames);
print(" dma="); printUInt64(pfn.DmaFrames);
print(" boot="); printUInt64(pfn.BootloaderFrames);
print(" pfn-db="); printUInt64(pfn.PfnDatabaseFrames);
print(" mmio="); printUInt64(pfn.MmioFrames); print("\n");
print(" buckets: clean-file="); printUInt64(pfn.CleanFileCacheFrames);
print(" (active="); printUInt64(pfn.ActiveCleanFileCacheFrames);
print(" standby="); printUInt64(pfn.StandbyCleanFileCacheFrames); print(")");
print(" image="); printUInt64(pfn.ImageFrames);
print(" (active="); printUInt64(pfn.ActiveImageFrames);
print(" standby="); printUInt64(pfn.StandbyImageFrames); print(")");
print(" mapped-file="); printUInt64(pfn.MappedFileFrames);
print(" anon="); printUInt64(pfn.AnonymousFrames);
print(" cow="); printUInt64(pfn.CowFrames);
print(" surface="); printUInt64(pfn.SurfaceFrames); print("\n");
print(" operations: alloc="); printUInt64(pfn.AllocationCount);
print(" free="); printUInt64(pfn.FreeCount);
print(" retain="); printUInt64(pfn.RetainCount);
print(" release="); printUInt64(pfn.ReleaseCount);
print(" pin="); printUInt64(pfn.PinCount);
print(" unpin="); printUInt64(pfn.UnpinCount); print("\n");
print(" failures: alloc="); printUInt64(pfn.FailedAllocations);
print(" contiguous="); printUInt64(pfn.FailedContiguousAllocations); print("\n");
print(" alloc reasons: invalid-range="); printUInt64(pfn.FailedInvalidRange);
print(" empty-range="); printUInt64(pfn.FailedEmptyRange);
print(" reserve-denied="); printUInt64(pfn.FailedReserveDenied);
print(" no-frame="); printUInt64(pfn.FailedNoFrame); print("\n");
print(" contig reasons: invalid="); printUInt64(pfn.FailedContiguousInvalidRequest);
print(" reserve-denied="); printUInt64(pfn.FailedContiguousReserveDenied);
print(" no-run="); printUInt64(pfn.FailedContiguousNoRun); print("\n");
print(" reclaim: attempts="); printUInt64(pfn.ReclaimAttempts);
print(" requested="); printUInt64(pfn.ReclaimPagesRequested);
print(" succeeded="); printUInt64(pfn.ReclaimPagesSucceeded);
print(" failed="); printUInt64(pfn.ReclaimPagesFailed);
print(" reentrant-skips="); printUInt64(pfn.ReclaimReentrantSkips); print("\n");
print("VAD faults:\n");
print(" resolve: calls="); printUInt64(vad.ResolveFaultCalls);
print(" resolved="); printUInt64(vad.ResolvedFaults);
print(" failed="); printUInt64(vad.FailedFaults); print("\n");
print(" failure reasons: protection="); printUInt64(vad.ProtectionFaults);
print(" no-vad="); printUInt64(vad.NoVadFaults);
print(" uncommitted="); printUInt64(vad.UncommittedFaults);
print(" noaccess="); printUInt64(vad.NoAccessFaults); print("\n");
print(" materialization: demand-zero="); printUInt64(vad.DemandZeroPages);
print(" zero-maps="); printUInt64(vad.ZeroPageMaps);
print(" zero-splits="); printUInt64(vad.ZeroPageCowSplits);
print(" ensure-calls="); printUInt64(vad.EnsureResidentCalls);
print(" ensure-pages="); printUInt64(vad.EnsureResidentPages);
print(" already-resident="); printUInt64(vad.AlreadyResidentPages); print("\n");
print(" cow: faults="); printUInt64(vad.CowFaults);
print(" copied="); printUInt64(vad.CowPagesCopied);
print(" views="); printUInt64(vad.CowViewsCreated);
print(" shared-pages="); printUInt64(vad.CowPagesShared); print("\n");
print(" file-backed: faults="); printUInt64(vad.FileBackedFaults);
print(" reads="); printUInt64(vad.FileBackedReads);
print(" read-fail="); printUInt64(vad.FileBackedReadFailures);
print(" discards="); printUInt64(vad.FileBackedDiscards); print("\n");
print(" mapped-file: shared-faults="); printUInt64(vad.FileBackedSharedWritableFaults);
print(" dirty-faults="); printUInt64(vad.FileBackedDirtyFaults);
print(" dirty-syncs="); printUInt64(vad.FileBackedDirtySyncs); print("\n");
print(" image-backed: faults="); printUInt64(vad.ImageBackedFaults);
print(" zero-faults="); printUInt64(vad.ImageBackedZeroFaults);
print(" private-faults="); printUInt64(vad.ImageBackedPrivateFaults); print("\n");
print(" image fixups: calls="); printUInt64(vad.ImageFixupPrivateCalls);
print(" private-pages="); printUInt64(vad.ImageFixupPrivatePages); print("\n");
print(" swap-backed: page-outs="); printUInt64(vad.SwapPageOuts);
print(" page-ins="); printUInt64(vad.SwapPageIns); print("\n");
print("Swap:\n");
print(" enabled: "); printUInt64(swap.Enabled); print("\n");
print(" slots: total="); printUInt64(swap.TotalSlots);
print(" used="); printUInt64(swap.UsedSlots);
print(" free="); printUInt64(swap.FreeSlots);
print(" high-water="); printUInt64(swap.HighWaterSlots); print("\n");
print(" io: out="); printUInt64(swap.PageOuts);
print(" in="); printUInt64(swap.PageIns);
print(" out-fail="); printUInt64(swap.PageOutFailures);
print(" in-fail="); printUInt64(swap.PageInFailures); print("\n");
print(" slots ops: alloc="); printUInt64(swap.SlotAllocations);
print(" free="); printUInt64(swap.SlotFrees);
print(" alloc-fail="); printUInt64(swap.SlotAllocationFailures); print("\n");
print("File cache:\n");
print(" lookups: total="); printUInt64(fileCache.Lookups);
print(" hits="); printUInt64(fileCache.Hits);
print(" misses="); printUInt64(fileCache.Misses); print("\n");
print(" loads: ok="); printUInt64(fileCache.Loads);
print(" fail="); printUInt64(fileCache.LoadFailures);
print(" races="); printUInt64(fileCache.RaceDiscards);
print(" waits="); printUInt64(fileCache.InflightWaits); print("\n");
print(" lifetime: resident="); printUInt64(fileCache.ResidentPages);
print(" active="); printUInt64(fileCache.ActivePages);
print(" standby="); printUInt64(fileCache.StandbyPages);
print(" max="); printUInt64(fileCache.MaxResidentPages);
print(" invalidations="); printUInt64(fileCache.Invalidations); print("\n");
print(" dirty/writeback: dirty="); printUInt64(fileCache.DirtyPages);
print(" max-dirty="); printUInt64(fileCache.MaxDirtyPages);
print(" marks="); printUInt64(fileCache.DirtyMarks);
print(" wb-req="); printUInt64(fileCache.WritebackRequests);
print(" wb-pages="); printUInt64(fileCache.WritebackPages);
print(" wb-bytes="); printUInt64(fileCache.WritebackBytes);
print(" wb-fail="); printUInt64(fileCache.WritebackFailures); print("\n");
print(" mapped dirty: syncs="); printUInt64(fileCache.MappedDirtySyncs);
print(" pages="); printUInt64(fileCache.MappedDirtyPages); print("\n");
print(" flushes: calls="); printUInt64(fileCache.FlushFileCalls);
print(" fail="); printUInt64(fileCache.FlushFileFailures); print("\n");
print(" reclaim: drops="); printUInt64(fileCache.Drops);
print(" standby="); printUInt64(fileCache.StandbyTransitions);
print(" standby-hits="); printUInt64(fileCache.StandbyHits);
print(" drop-fail="); printUInt64(fileCache.DropFailures); print("\n");
print("Filesystem:\n");
print(" path cache: lookups="); printUInt64(filesystem.PathLookups);
print(" hits="); printUInt64(filesystem.PathCacheHits);
print(" misses="); printUInt64(filesystem.PathCacheMisses);
print(" stores="); printUInt64(filesystem.PathCacheStores); print("\n");
print(" invalidation: count="); printUInt64(filesystem.PathCacheInvalidations);
print(" generation="); printUInt64(filesystem.PathCacheGeneration); print("\n");
print(" directory search: searches="); printUInt64(filesystem.DirectorySearches);
print(" blocks="); printUInt64(filesystem.DirectoryBlocksRead);
print(" entries="); printUInt64(filesystem.DirectoryEntriesScanned); print("\n");
print(" data read spans: runs="); printUInt64(filesystem.DataReadRuns);
print(" sectors="); printUInt64(filesystem.DataReadSectors);
print(" merges="); printUInt64(filesystem.DataReadRunMerges);
print(" max-sectors="); printUInt64(filesystem.MaxDataReadSpanSectors); print("\n");
print("Disk I/O:\n");
print(" devices: registered="); printUInt64(disk.RegisteredDisks); print("\n");
print(" reads: requests="); printUInt64(disk.ReadRequests);
print(" sectors="); printUInt64(disk.ReadSectors);
print(" max-sectors="); printUInt64(disk.MaxReadSectors); print("\n");
print(" writes: requests="); printUInt64(disk.WriteRequests);
print(" sectors="); printUInt64(disk.WriteSectors);
print(" max-sectors="); printUInt64(disk.MaxWriteSectors); print("\n");
print("Surfaces:\n");
print(" lifetime: created="); printUInt64(surface.CreatedSurfaces);
print(" destroyed="); printUInt64(surface.DestroyedSurfaces);
print(" live="); printUInt64(surface.LiveSurfaces); print("\n");
print(" live memory: pages="); printUInt64(surface.LivePages);
print(" bytes="); printUInt64(surface.LiveBytes); print("\n");
print(" maps/commits: maps="); printUInt64(surface.MapCalls);
print(" commits="); printUInt64(surface.CommitCalls);
print(" input-rects="); printUInt64(surface.CommitRectInputs); print("\n");
print(" commit work: clipped="); printUInt64(surface.CommitClippedRects);
print(" empty="); printUInt64(surface.CommitEmptyClips); print("\n");
print(" physical present: calls="); printUInt64(surface.PhysicalPresentCalls);
print(" bytes="); printUInt64(surface.PhysicalPresentBytesCopied); print("\n");
print("Page tables:\n");
print(" leaf mappings: "); printUInt64(pte.CurrentLeafMappings); print("\n");
print(" page-table pages: "); printUInt64(pte.PageTablePagesAllocated); print("\n");
print(" map/unmap: map="); printUInt64(pte.MapCalls);
print(" failed="); printUInt64(pte.MapFailures);
print(" unmap="); printUInt64(pte.UnmapCalls);
print(" failed="); printUInt64(pte.UnmapFailures); print("\n");
print(" protect: calls="); printUInt64(pte.ProtectCalls);
print(" failed="); printUInt64(pte.ProtectFailures); print("\n");
print(" query: total="); printUInt64(pte.QueryCalls);
print(" failed="); printUInt64(pte.QueryFailures);
print(" translate="); printUInt64(pte.TranslateCalls); print("\n");
print(" generic: "); printUInt64(pte.QueryByPurpose[SYS_PTE_QUERY_GENERIC]);
print(" failed="); printUInt64(pte.QueryFailuresByPurpose[SYS_PTE_QUERY_GENERIC]); print("\n");
print(" user-probe: "); printUInt64(pte.QueryByPurpose[SYS_PTE_QUERY_USER_PROBE]);
print(" failed="); printUInt64(pte.QueryFailuresByPurpose[SYS_PTE_QUERY_USER_PROBE]); print("\n");
print(" heap: "); printUInt64(pte.QueryByPurpose[SYS_PTE_QUERY_HEAP]);
print(" failed="); printUInt64(pte.QueryFailuresByPurpose[SYS_PTE_QUERY_HEAP]); print("\n");
print(" vad: "); printUInt64(pte.QueryByPurpose[SYS_PTE_QUERY_VAD]);
print(" failed="); printUInt64(pte.QueryFailuresByPurpose[SYS_PTE_QUERY_VAD]); print("\n");
print(" debug: "); printUInt64(pte.QueryByPurpose[SYS_PTE_QUERY_DEBUG]);
print(" failed="); printUInt64(pte.QueryFailuresByPurpose[SYS_PTE_QUERY_DEBUG]); print("\n");
print(" self-test: "); printUInt64(pte.QueryByPurpose[SYS_PTE_QUERY_SELF_TEST]);
print(" failed="); printUInt64(pte.QueryFailuresByPurpose[SYS_PTE_QUERY_SELF_TEST]); print("\n");
print(" tlb: local="); printUInt64(pte.LocalFlushes);
print(" global="); printUInt64(pte.GlobalFlushes);
print(" new-map-skip="); printUInt64(pte.NewMappingNoFlushes);
print(" replace-flush="); printUInt64(pte.ReplacedMappingFlushes); print("\n");
print(" shootdowns: requests="); printUInt64(pte.ShootdownRequests);
print(" targets="); printUInt64(pte.ShootdownTargetCpus);
print(" skipped="); printUInt64(pte.ShootdownSkippedNoTargets);
print(" acks="); printUInt64(pte.ShootdownAcks);
print(" timeouts="); printUInt64(pte.ShootdownTimeouts); print("\n");
SysFreeVm(cpuBuffer);
}
// Implements the cmd time operation.
static void cmd_time(void) {
SYS_SYSTEM_TIME t;
uint32_t status = SysGetSystemTime(&t);
if (status != 0) {
print("time: failed: ");
printUInt(status);
print("\n");
return;
}
printUIntZeroWidth(t.Year, 4); print("-");
printUIntZeroWidth(t.Month, 2); print("-");
printUIntZeroWidth(t.Day, 2); print(" ");
printUIntZeroWidth(t.Hour, 2); print(":");
printUIntZeroWidth(t.Minute, 2); print(":");
printUIntZeroWidth(t.Second, 2); print(".");
printUIntZeroWidth(t.Millisecond, 3);
print(" epoch="); printUInt64(t.EpochSeconds);
print(" flags=0x"); printUInt(t.Flags);
if (t.Flags & SYS_TIME_FLAG_TZ_KNOWN) {
print(" tz="); printInt(t.TimeZoneMinutes);
} else {
print(" tz=unspecified");
}
print("\n");
}
// Prints display Caps.
static void printDisplayCaps(uint32_t caps) {
bool any = false;
if (caps & DISPLAY_CAP_FRAMEBUFFER) { print("framebuffer"); any = true; }
if (caps & DISPLAY_CAP_SOFTWARE_CURSOR) { if (any) print(","); print("software-cursor"); any = true; }
if (caps & DISPLAY_CAP_HARDWARE_CURSOR) { if (any) print(","); print("hardware-cursor"); any = true; }
if (caps & DISPLAY_CAP_ACCEL_FILL) { if (any) print(","); print("accel-fill"); any = true; }
if (caps & DISPLAY_CAP_ACCEL_COPY) { if (any) print(","); print("accel-copy"); any = true; }
if (caps & DISPLAY_CAP_PRESENT_SYNC) { if (any) print(","); print("present-sync"); any = true; }
if (caps & DISPLAY_CAP_VBLANK) { if (any) print(","); print("vblank"); any = true; }
if (caps & DISPLAY_CAP_3D) { if (any) print(","); print("3d"); any = true; }
if (!any) print("none");
}
// Prints display Stats.
static void printDisplayStats(const char* title, const DISPLAY_STATS* st) {
print(title); print(":\n");
print(" blit: "); printUInt64(st->BlitCount); print("\n");
print(" fill: "); printUInt64(st->FillRectCount); print("\n");
print(" copy: "); printUInt64(st->CopyRectCount); print("\n");
print(" read: "); printUInt64(st->ReadRectCount); print("\n");
print(" present: "); printUInt64(st->PresentCount); print(" rects="); printUInt64(st->PresentRectCount);
print(" direct="); printUInt64(st->DirectPresentCount); print("\n");
print(" dirty: "); printUInt64(st->DirtyRectCount); print(" all="); printUInt64(st->DirtyAllCount); print("\n");
print(" bytes: logical="); printUInt64(st->BytesCopied);
print(" scanout="); printUInt64(st->ScanoutBytes); print("\n");
print(" sync: "); printUInt64(st->SyncCount); print("\n");
print(" cursor: move="); printUInt64(st->CursorMoveCount);
print(" show="); printUInt64(st->CursorShowCount);
print(" hide="); printUInt64(st->CursorHideCount); print("\n");
}
// Implements the cmd display operation.
static void cmd_display(void) {
SYS_DISPLAY_INFO info;
uint32_t status = SysQueryDisplayInfo(&info);
if (status != 0) {
print("display: query failed: ");
printUInt(status);
print("\n");
return;
}
print("Display:\n");
print(" primary: "); print(info.PrimaryName[0] ? info.PrimaryName : "?"); print("\n");
print(" devices: "); printUInt(info.DeviceCount); print("\n");
print(" mode: "); printUInt(info.Mode.Width); print("x"); printUInt(info.Mode.Height);
print(" stride="); printUInt(info.Mode.Stride); print(" format="); printUInt((uint32_t)info.Mode.Format); print("\n");
print(" caps: 0x"); printHex32(info.Caps); print(" ["); printDisplayCaps(info.Caps); print("]\n");
print(" scanout: ");
print((info.Flags & DISPLAY_INFO_FLAG_PAT_WC_AVAILABLE) ? "PAT WC available" : "PAT WC unavailable");
print("\n");
printDisplayStats("Manager counters", &info.ManagerStats);
printDisplayStats("Provider counters", &info.DeviceStats);
}
typedef struct SHELL_FB_BENCH_RESULT {
uint32_t Width;
uint32_t Height;
uint32_t Frames;
uint32_t Status;
uint64_t ElapsedTicks;
uint64_t Frequency;
uint64_t CommitBytes;
} SHELL_FB_BENCH_RESULT;
// Computes a decimal fixed-point ratio with one digit after the decimal point.
static uint64_t shellRatioTenths(uint64_t numerator, uint64_t denominator) {
if (!denominator)
return 0;
if (numerator > UINT64_MAX / 10u)
return (numerator / denominator) * 10u;
return (numerator * 10u) / denominator;
}
// Fills a benchmark surface with a deterministic high-contrast pattern.
static void shellFillBenchmarkSurface(uint32_t* pixels,
uint32_t pitchPixels,
uint32_t width,
uint32_t height) {
for (uint32_t y = 0; y < height; y++) {
uint32_t* row = pixels + (size_t)y * pitchPixels;
for (uint32_t x = 0; x < width; x++) {
uint32_t red = (x * 255u) / (width ? width : 1u);
uint32_t green = (y * 255u) / (height ? height : 1u);
uint32_t blue = ((x ^ y) & 0xFFu);
row[x] = (red << 16) | (green << 8) | blue;
}
}
}
// Runs one synchronous surface-commit benchmark case.
static void shellRunFramebufferBenchmark(uint32_t width,
uint32_t height,
uint32_t frames,
uint64_t frequency,
SHELL_FB_BENCH_RESULT* result) {
memset(result, 0, sizeof(*result));
result->Width = width;
result->Height = height;
result->Frames = frames;
result->Frequency = frequency;
uint32_t surface = 0;
SYS_CREATE_SURFACE_REQUEST create;
memset(&create, 0, sizeof(create));
create.Size = sizeof(create);
create.Width = width;
create.Height = height;
create.Format = SYS_SURFACE_FORMAT_XRGB8888;
create.Flags = SYS_SURFACE_FLAG_NONE;
create.HandleOut = &surface;
uint32_t status = SysCreateSurface(&create);
if (status != NTLSTATUS_SUCCESS || !surface) {
result->Status = status ? status : NTLSTATUS_FAILURE;
return;
}
void* base = 0;
uint32_t pitchBytes = 0;
status = SysMapSurface(surface, SYS_SURFACE_MAP_READ | SYS_SURFACE_MAP_WRITE,
&base, &pitchBytes);
if (status != NTLSTATUS_SUCCESS || !base || pitchBytes < width * sizeof(uint32_t)) {
result->Status = status ? status : NTLSTATUS_FAILURE;
SysCloseHandle(surface);
return;
}
shellFillBenchmarkSurface((uint32_t*)base, pitchBytes / sizeof(uint32_t), width, height);
DISPLAY_RECT rect = { 0, 0, (int32_t)width, (int32_t)height };
for (uint32_t i = 0; i < 2 && status == NTLSTATUS_SUCCESS; ++i)
status = SysCommitSurface(surface, &rect, 1, 0);
uint64_t begin = 0;
uint64_t end = 0;
uint32_t completed = 0;
if (status == NTLSTATUS_SUCCESS) {
begin = SysGetTick();
for (; completed < frames; ++completed) {
status = SysCommitSurface(surface, &rect, 1, 0);
if (status != NTLSTATUS_SUCCESS)
break;
}
end = SysGetTick();
}
result->Frames = completed;
result->Status = status;
result->ElapsedTicks = end - begin;
result->CommitBytes = (uint64_t)width * (uint64_t)height * sizeof(uint32_t) * completed;
(void)SysUnmapSurface(base);
SysCloseHandle(surface);
}
// Prints one framebuffer benchmark result.
static void shellPrintFramebufferBenchmark(const char* name,
const SHELL_FB_BENCH_RESULT* result) {
print(" "); print(name); print(" ");
printUInt(result->Width); print("x"); printUInt(result->Height); print(": ");
if (result->Status != NTLSTATUS_SUCCESS || !result->ElapsedTicks || !result->Frequency) {
print("failed status=0x"); printHex32(result->Status); print("\n");
return;
}
uint64_t elapsedUs = SysTicksToMicroseconds(result->ElapsedTicks, result->Frequency);
uint64_t fpsTenths = shellRatioTenths((uint64_t)result->Frames * result->Frequency,
result->ElapsedTicks);
uint64_t mibTenths = shellRatioTenths(result->CommitBytes * result->Frequency,
result->ElapsedTicks * 1024u * 1024u);
print("frames="); printUInt(result->Frames);
print(" time="); printUInt64(elapsedUs / 1000u); print(" ms");
print(" fps="); printUInt64(fpsTenths / 10u); print("."); printUInt64(fpsTenths % 10u);
print(" payload="); printUInt64(mibTenths / 10u); print("."); printUInt64(mibTenths % 10u); print(" MiB/s");
print(" bytes="); printUInt64(result->CommitBytes);
print("\n");
}
// Benchmarks surface commit bookkeeping without implying physical presentation.
static void cmd_surfbench(void) {
SYS_DISPLAY_INFO info;
uint32_t status = SysQueryDisplayInfo(&info);
if (status != NTLSTATUS_SUCCESS) {
print("surfbench: display query failed status=0x"); printHex32(status); print("\n");
return;
}
uint64_t frequency = 0;
status = SysGetTickFrequency(&frequency);
if (status != NTLSTATUS_SUCCESS || !frequency) {
print("surfbench: timer query failed status=0x"); printHex32(status); print("\n");
return;
}
uint32_t doomWidth = info.Mode.Width < 960u ? info.Mode.Width : 960u;
uint32_t doomHeight = info.Mode.Height < 600u ? info.Mode.Height : 600u;
uint32_t fullWidth = info.Mode.Width;
uint32_t fullHeight = info.Mode.Height;
uint64_t targetBytes = 128ull * 1024ull * 1024ull;
uint64_t doomFrameBytes = (uint64_t)doomWidth * doomHeight * sizeof(uint32_t);
uint64_t fullFrameBytes = (uint64_t)fullWidth * fullHeight * sizeof(uint32_t);
uint32_t doomFrames = doomFrameBytes ? (uint32_t)((targetBytes + doomFrameBytes - 1u) / doomFrameBytes) : 1u;
uint32_t fullFrames = fullFrameBytes ? (uint32_t)((targetBytes + fullFrameBytes - 1u) / fullFrameBytes) : 1u;
if (doomFrames < 8u) doomFrames = 8u;
if (doomFrames > 128u) doomFrames = 128u;
if (fullFrames < 8u) fullFrames = 8u;
if (fullFrames > 64u) fullFrames = 64u;
print("surfbench: commit notifications only; scanout is DWM-owned\n");
SHELL_FB_BENCH_RESULT doom;
SHELL_FB_BENCH_RESULT full;
shellRunFramebufferBenchmark(doomWidth, doomHeight, doomFrames, frequency, &doom);
shellRunFramebufferBenchmark(fullWidth, fullHeight, fullFrames, frequency, &full);
NtlConsoleClear(SYS_HANDLE_INVALID, 0x00012456u);
print("Framebuffer benchmark:\n");
print(" provider: "); print(info.PrimaryName[0] ? info.PrimaryName : "?");
print(" mode="); printUInt(info.Mode.Width); print("x"); printUInt(info.Mode.Height);
print(" stride="); printUInt(info.Mode.Stride);
print(" cache="); print((info.Flags & DISPLAY_INFO_FLAG_PAT_WC_AVAILABLE) ? "PAT-WC" : "fallback");
print("\n");
shellPrintFramebufferBenchmark("doom", &doom);
shellPrintFramebufferBenchmark("full", &full);
}
// Implements the cmd mem operation.
static void cmd_mem(void) {
SYS_MEMORY_STATUS st;
if (SysGetMemoryStatus(&st) != 0) {
print("mem: failed\n");
return;
}
print("Memory Status:\n");
print(" Free physical: ");
printSizeKiB(st.FreePhysicalBytes);
print("\n Reclaimable: ");
printSizeKiB(st.ReclaimablePhysicalBytes);
print("\n Available physical: ");
printSizeKiB(st.AvailablePhysicalBytes);
print("\n Pinned physical: ");
printSizeKiB(st.PinnedPhysicalBytes);
print("\n Non-evictable: ");
printSizeKiB(st.NonEvictablePhysicalBytes);
print("\n User frames: ");
printSizeKiB(st.UserPhysicalBytes);
print("\n Page tables: ");
printSizeKiB(st.PageTablePhysicalBytes);
print("\n Kernel pool: ");
printSizeKiB(st.KernelPoolBytes);
print("\n User heap: ");
printSizeKiB(st.UserHeapBytes);
print("\n");
}
// Processes state Name.
static const char* processStateName(uint32_t state) {
switch (state) {
case SYS_PROCESS_STATE_RUNNING: return "run";
case SYS_PROCESS_STATE_TERMINATING: return "term";
case SYS_PROCESS_STATE_EXITED: return "exit";
case SYS_PROCESS_STATE_CONSTRUCTING: return "build";
default: return "?";
}
}
// Names public thread states.
static const char* threadStateName(uint32_t state) {
switch (state) {
case SYS_THREAD_STATE_READY: return "ready";
case SYS_THREAD_STATE_RUNNING: return "run";
case SYS_THREAD_STATE_WAITING: return "wait";
case SYS_THREAD_STATE_DEAD: return "dead";
case SYS_THREAD_STATE_SUSPENDED: return "suspend";
default: return "?";
}
}
// Names public wait object types.
static const char* threadWaitName(uint32_t waitType) {
switch (waitType) {
case SYS_THREAD_WAIT_NONE: return "-";
case SYS_THREAD_WAIT_PROCESS: return "process";
case SYS_THREAD_WAIT_THREAD: return "thread";
case SYS_THREAD_WAIT_MUTEX: return "mutex";
case SYS_THREAD_WAIT_SEMAPHORE: return "sem";
case SYS_THREAD_WAIT_EVENT: return "event";
case SYS_THREAD_WAIT_QUEUE: return "queue";
case SYS_THREAD_WAIT_FILE: return "file";
case SYS_THREAD_WAIT_DIR: return "dir";
case SYS_THREAD_WAIT_ASYNC_IO: return "async";
case SYS_THREAD_WAIT_SOCKET: return "socket";
case SYS_THREAD_WAIT_DEVICE: return "device";
case SYS_THREAD_WAIT_DRIVER: return "driver";
case SYS_THREAD_WAIT_USB_DEVICE: return "usbdev";
case SYS_THREAD_WAIT_USB_PIPE: return "usbpipe";
case SYS_THREAD_WAIT_FILE_MAPPING: return "mapping";
case SYS_THREAD_WAIT_SURFACE: return "surface";
case SYS_THREAD_WAIT_PIPE: return "pipe";
default: return "unknown";
}
}
// Prints thread status flags.
static void printThreadFlags(uint32_t flags) {
char buf[8];
size_t n = 0;
if (flags & SYS_THREAD_FLAG_CURRENT) buf[n++] = '*';
if (flags & SYS_THREAD_FLAG_IDLE) buf[n++] = 'I';
if (flags & SYS_THREAD_FLAG_KERNEL) buf[n++] = 'K';
if (flags & SYS_THREAD_FLAG_QUEUED) buf[n++] = 'Q';
if (flags & SYS_THREAD_FLAG_ALERTABLE_WAIT) buf[n++] = 'A';
if (flags & SYS_THREAD_FLAG_KERNEL_APC_PENDING) buf[n++] = 'k';
if (flags & SYS_THREAD_FLAG_USER_APC_PENDING) buf[n++] = 'u';
if (n == 0) buf[n++] = '-';
buf[n] = '\0';
printStringWidth(buf, 7);
}
// Implements the cmd ps operation.
static void cmd_ps(void) {
SYS_PROCESS_INFO procs[MAX_PROCS];
size_t count = 0;
uint32_t status = SysGetProcessList(procs, MAX_PROCS, &count);
if (status != 0) {
print("ps: failed to retrieve process list\n");
return;
}
print("Processes (Count: ");
printUInt((uint32_t)count);
print("):\n");
print(" PID State Thr Hnd UserKiB ImageKiB Flags Name\n");
print(" Flags: S=system I=idle P=protected *=current T=terminating X=exited.\n");
size_t displayCount = count < MAX_PROCS ? count : MAX_PROCS;
for (size_t i = 0; i < displayCount; i++) {
SYS_PROCESS_INFO* p = &procs[i];
char flags[7];
size_t flagLen = 0;
if (p->Flags & SYS_PROCESS_FLAG_SYSTEM) flags[flagLen++] = 'S';
if (p->Flags & SYS_PROCESS_FLAG_IDLE) flags[flagLen++] = 'I';
if (p->Flags & SYS_PROCESS_FLAG_TERMINATION_PROTECTED) flags[flagLen++] = 'P';
if (p->Flags & SYS_PROCESS_FLAG_CURRENT) flags[flagLen++] = '*';
if (p->Flags & SYS_PROCESS_FLAG_TERMINATING) flags[flagLen++] = 'T';
if (p->Flags & SYS_PROCESS_FLAG_EXITED) flags[flagLen++] = 'X';
if (flagLen == 0) flags[flagLen++] = '-';
flags[flagLen] = '\0';
print(" ");
printUIntWidth(p->ProcessId, 3);
print(" ");
printStringWidth(processStateName(p->State), 5);
print(" ");
printUIntWidth(p->ThreadCount, 3);
print(" ");
printUIntWidth(p->HandleCount, 3);
print(" ");
printUInt64Width((uint64_t)p->UserCommittedBytes / 1024u, 7);
print(" ");
printUInt64Width((uint64_t)p->ImageSize / 1024u, 8);
print(" ");
printStringWidth(flags, 5);
print(" ");
print(p->Name);
print("\n");
}
if (count > MAX_PROCS) {
print(" ... and ");
printUInt((uint32_t)(count - MAX_PROCS));
print(" more processes.\n");
}
}
// Implements the cmd threads operation.
static void cmd_threads(const char* args) {
uint32_t pid = 0;
if (!parseUInt(args, &pid)) {
print("threads: usage: threads <pid>\n");
return;
}
SYS_THREAD_INFO threads[MAX_THREADS];
size_t count = 0;
uint32_t status = SysGetThreadList(pid, threads, MAX_THREADS, &count);
if (status != 0) {
print("threads: query failed status=");
printUInt(status);
print("\n");
return;
}
print("Threads for PID ");
printUInt(pid);
print(" (Count: ");
printUInt((uint32_t)count);
print("):\n");
print(" TID State Base Eff CPU LastCPU QRem QTick Burst Wait WStat Flags Name\n");
print(" Flags: *=current I=idle K=kernel Q=queued A=alertable k=kernel-apc u=user-apc.\n");
size_t displayCount = count < MAX_THREADS ? count : MAX_THREADS;
for (size_t i = 0; i < displayCount; i++) {
SYS_THREAD_INFO* t = &threads[i];
print(" ");
printUIntWidth(t->ThreadId, 3);
print(" ");
printStringWidth(threadStateName(t->State), 5);
print(" ");
if (t->BaseSchedulingClass == SYS_SCHEDULING_REALTIME) print("R"); else print("N");
printUIntWidth(t->BasePriority, 2);
print(" ");
if (t->EffectiveSchedulingClass == SYS_SCHEDULING_REALTIME) print("R"); else print("N");
printUIntWidth(t->EffectivePriority, 2);
print(" ");
if (t->RunningCpu == 0xffffffffu) printStringWidth("-", 3);
else printUIntWidth(t->RunningCpu, 3);
print(" ");
if (t->LastCpu == 0xffffffffu) printStringWidth("-", 7);
else printUIntWidth(t->LastCpu, 7);
print(" ");
printUIntWidth(t->QuantumRemaining, 4);
print(" ");
printUIntWidth(t->QuantumTicks, 5);
print(" ");
printUIntWidth(t->CpuBurstTicks, 5);
print(" ");
printStringWidth(threadWaitName(t->WaitObjectType), 8);
print(" ");
printUIntWidth(t->WaitStatus, 5);
print(" ");
printThreadFlags(t->Flags);
print(" ");
print(t->Name[0] ? t->Name : "-");
print("\n");
}
if (count > MAX_THREADS) {
print(" ... and ");
printUInt((uint32_t)(count - MAX_THREADS));
print(" more threads.\n");
}
}
static void cmd_kill(const char* args) {
uint32_t pid = 0;
if (!parseUInt(args, &pid)) { print("kill: usage: kill <pid>\n"); return; }
uint32_t hProc = 0;
uint32_t status = SysOpenProcess(pid, SYS_PROCESS_RIGHT_TERMINATE, &hProc);
if (status == 0) {
status = SysKillProcess(hProc, (int32_t)NTLSTATUS_PROCESS_KILLED);
SysCloseHandle(hProc);
}
if (status == NTLSTATUS_ACCESS_DENIED) {
print("kill: process ");
printUInt(pid);
print(" is termination-protected.\n");
} else if (status != 0) {
print("shell: failed to kill process ");
printUInt(pid);
print(", error code: ");
printUInt(status);
print("\n");
} else {
print("Process ");
printUInt(pid);
print(" terminated successfully.\n");
}
}
// Implements the cmd write operation.
static void cmd_write(const char* args) {
char filename[MAX_CMD]; int i = 0;
while (args[i] != ' ' && args[i] != '\0' && i < MAX_CMD - 1) {
filename[i] = args[i]; i++;
}
filename[i] = '\0';
if (args[i] == '\0' || args[i+1] == '\0') { print("write: usage: write <filename> <text>\n"); return; }
uint32_t hFile;
if (create_file(filename, &hFile) != 0) { print("write: could not create file\n"); return; }
size_t written;
SYS_FILE_IO_REQUEST writeReq = SysMakeFileIoRequest(hFile, args + i + 1, strlen(args + i + 1), &written);
SysWriteFile(&writeReq);
SysCloseHandle(hFile);
print("File written successfully.\n");
}
#define SHELL_DIR_INITIAL_CAPACITY 64u
// Compares two names using case-insensitive order with a stable case tie-breaker.
static int shellCompareNames(const char* a, const char* b) {
size_t i = 0;
if (!a) a = "";
if (!b) b = "";
while (true) {
char ca = shellAsciiLower(a[i]);
char cb = shellAsciiLower(b[i]);
if (ca != cb)
return (ca < cb) ? -1 : 1;
if (ca == '\0')
break;
i++;
}
return strcmp(a, b);
}
// Compares two directory entries by display name.
static int shellCompareDirEntries(const SYS_DIR_ENTRY* a, const SYS_DIR_ENTRY* b) {
return shellCompareNames(a->Name, b->Name);
}
// Allocates a directory-entry array from VM so large listings do not consume stack.
static uint32_t shellAllocDirEntries(uint32_t capacity, SYS_DIR_ENTRY** entriesOut) {
void* base = 0;
size_t bytes = (size_t)capacity * sizeof(SYS_DIR_ENTRY);
size_t pages = (bytes + 4095u) / 4096u;
if (pages == 0) pages = 1;
SYS_ALLOC_VM_REQUEST req;
memset(&req, 0, sizeof(req));
req.Size = sizeof(req);
req.Protect = SYS_VM_READWRITE;
req.Flags = SYS_VM_FLAG_NONE;
req.PageCount = pages;
req.BaseOut = &base;
uint32_t status = SysAllocVm(&req);
if (status != 0 || !base) {
*entriesOut = 0;
return status ? status : 1;
}
*entriesOut = (SYS_DIR_ENTRY*)base;
return 0;
}
// Grows a directory-entry array while preserving already-read entries.
static uint32_t shellGrowDirEntries(SYS_DIR_ENTRY** entries, uint32_t* capacity, uint32_t count) {
uint32_t oldCapacity = *capacity;
uint32_t newCapacity = oldCapacity ? oldCapacity * 2u : SHELL_DIR_INITIAL_CAPACITY;
SYS_DIR_ENTRY* next = 0;
uint32_t status = shellAllocDirEntries(newCapacity, &next);
if (status != 0)
return status;
if (*entries && count)
memcpy(next, *entries, (size_t)count * sizeof(SYS_DIR_ENTRY));
if (*entries)
SysFreeVm(*entries);
*entries = next;
*capacity = newCapacity;
return 0;
}
// Sorts directory entries alphabetically.
static void shellSortDirEntries(SYS_DIR_ENTRY* entries, uint32_t count) {
for (uint32_t i = 1; i < count; i++) {
SYS_DIR_ENTRY current = entries[i];
uint32_t j = i;
while (j > 0 && shellCompareDirEntries(&current, &entries[j - 1]) < 0) {
entries[j] = entries[j - 1];
j--;
}
entries[j] = current;
}
}
// Prints one directory entry in cmd dir format.
static void shellPrintDirEntry(const SYS_DIR_ENTRY* ke) {
printDirTime(&ke->LastWriteTime);
if (ke->Attr & 0x10) {
print("<DIR> ");
print(ke->Name);
} else {
print(" ");
print(ke->Name);
print(" (");
printUInt64(ke->FileSize);
print(" bytes)");
}
print("\n");
}
// Prints one RSSRV namespace kind label.
static void shellPrintResourceKind(uint32_t kind) {
if (kind == NTL_RESOURCE_KIND_NAMESPACE_DIRECTORY) print("<NSDIR> ");
else if (kind == NTL_RESOURCE_KIND_SYMBOLIC_LINK) print("<SYMLINK> ");
else if (kind == NTL_RESOURCE_KIND_VOLUME) print("<VOLUME> ");
else if (kind == NTL_RESOURCE_KIND_DIRECTORY) print("<DIRCAP> ");
else if (kind == NTL_RESOURCE_KIND_DEVICE) print("<DEVICE> ");
else print("<OBJECT> ");
}
// Handles dir for an exact RSSRV namespace directory and returns whether it owned the request.
static bool shellTryResourceDir(const char* target) {
if (!target || target[0] != '/') return false;
SYS_HANDLE session = SYS_HANDLE_INVALID;
if (!KSUCCESS(NtlResourceConnect(&session))) return false;
uint32_t kind = NTL_RESOURCE_KIND_INVALID;
KSTATUS status = NtlResourceQuery(session, SysSvFromCstr(target), &kind);
if (!KSUCCESS(status) || kind != NTL_RESOURCE_KIND_NAMESPACE_DIRECTORY) {
(void)NtlResourceClose(session);
return false;
}
NTL_RESOURCE_ENUM_CURSOR cursor;
memset(&cursor, 0, sizeof(cursor));
for (;;) {
NTL_RESOURCE_ENUM_ENTRY entry;
status = NtlResourceEnumerate(session, SysSvFromCstr(target), &cursor, &entry);
if (status == NTLSTATUS_NO_MORE_FILES) break;
if (!KSUCCESS(status)) {
print("dir: namespace enumeration failed, status=0x");
printHex32(status);
print("\n");
break;
}
shellPrintResourceKind(entry.Kind);
print(entry.Name);
if (entry.Kind == NTL_RESOURCE_KIND_NAMESPACE_DIRECTORY) print("/");
print("\n");
}
(void)NtlResourceClose(session);
return true;
}
// Implements the cmd dir operation.
static void cmd_dir(const char* path) {
uint32_t hDir;
const char* target = (path && *path != '\0') ? path : ".";
if (shellTryResourceDir(target)) return;
uint32_t st = open_dir(target, &hDir);
if (st != 0) {
print("dir: failed to open directory, status=0x");
printHex32(st);
print("\n");
return;
}
SYS_DIR_ENTRY* entries = 0;
uint32_t count = 0;
uint32_t capacity = 0;
while (true) {
SYS_DIR_ENTRY ke;
st = SysReadDir(hDir, &ke);
if (st != 0)
break;
if (count == capacity) {
st = shellGrowDirEntries(&entries, &capacity, count);
if (st != 0) {
print("dir: out of memory, status=0x");
printHex32(st);
print("\n");
SysCloseHandle(hDir);
if (entries) SysFreeVm(entries);
return;
}
}
entries[count++] = ke;
}
SysCloseHandle(hDir);
shellSortDirEntries(entries, count);
for (uint32_t i = 0; i < count; i++)
shellPrintDirEntry(&entries[i]);
if (entries)
SysFreeVm(entries);
}
// Implements the cmd type operation.
static void cmd_type(const char* filename) {
uint32_t hFile;
if (open_file(filename, &hFile) != 0) { print("type: cannot open file\n"); return; }
char buffer[512]; size_t bytesRead;
while (true) {
SYS_FILE_IO_REQUEST readReq = SysMakeFileIoRequest(hFile, buffer, sizeof(buffer) - 1, &bytesRead);
if (SysReadFile(&readReq) != 0 || bytesRead == 0) break;
buffer[bytesRead] = '\0'; print(buffer);
}
SysCloseHandle(hFile); print("\n");
}
// Implements the extract Program Path operation.
static bool extractProgramPath(const char* cmdline, char* out, size_t outSize) {
if (!cmdline || !out || outSize == 0) return false;
while (*cmdline == ' ' || *cmdline == '\t') cmdline++;
if (*cmdline == '\0') return false;
size_t pos = 0;
if (*cmdline == '"') {
cmdline++;
while (*cmdline && *cmdline != '"' && pos + 1 < outSize)
out[pos++] = *cmdline++;
} else {
while (*cmdline && *cmdline != ' ' && *cmdline != '\t' && pos + 1 < outSize)
out[pos++] = *cmdline++;
}
out[pos] = '\0';
return pos != 0;
}
// Returns whether one input key is currently held.
static bool shellIsKeyDown(INPUT_KEY key) {
bool down = false;
return NtlInputIsKeyDown(key, &down) == NTLSTATUS_SUCCESS && down;
}
// Waits for a foreground process while polling Ctrl-C without consuming child input.
static uint32_t waitForegroundProcess(uint32_t hProc) {
bool sentBreak = false;
while (true) {
uint32_t status = SysWaitSingle(hProc,
SYS_WAIT_FLAG_NONE,
SHELL_FOREGROUND_POLL_MS);
if (status == NTLSTATUS_SUCCESS)
return status;
if (status != NTLSTATUS_TIMEOUT)
return status;
uint32_t modifiers = NtlInputGetKeyModifiers();
if (!sentBreak && (modifiers & INPUT_MOD_CTRL) &&
shellIsKeyDown(INPUT_KEY_C)) {
print("^C\n");
uint32_t killStatus = SysKillProcess(
hProc,
(int32_t)NTLSTATUS_PROCESS_KILLED);
if (killStatus != NTLSTATUS_SUCCESS) {
print("shell: foreground termination failed status=");
printUInt(killStatus);
print("\n");
return killStatus;
}
sentBreak = true;
}
}
}
// Run one command.
static int runCommand(const char* cmd) {
if (!cmd || *cmd == '\0') return 0;
if (strcmp(cmd, "exit") == 0) return 1;
if (strcmp(cmd, "help") == 0) { cmd_help(); return 0; }
if (strcmp(cmd, "clear") == 0) { (void)NtlConsoleClear(SYS_HANDLE_INVALID, 0x012456); return 0; }
if (strncmp(cmd, "crash", 5) == 0) {
// Check the sub-option trailing "crash " (offset 6).
if (strcmp(cmd + 6, "void") == 0) {
// Jumping into the void.
void (*invalid_func)(void) = NULL;
invalid_func();
return 0;
}
else if (strcmp(cmd + 6, "noncanonical") == 0) {
// Non-canonical pointer dereference.
volatile int* ptr = (volatile int*)0x4242424242424242ULL;
*ptr = 1337;
return 0;
}
else if (strcmp(cmd + 6, "ud2") == 0) {
__ud2();
return 0;
}
else if (strcmp(cmd + 6, "nx") == 0) {
// NX / DEP Violation.
unsigned char code[] = { 0xC3 };
void (*execute_stack)(void) = (void (*)(void))code;
execute_stack();
return 0;
}
else if (strcmp(cmd + 6, "divzero") == 0) {
// Division by zero.
volatile int zero = 0;
volatile int result = 1 / zero;
(void)result;
return 0;
}
else {
// Default fallback if just "crash" or an unknown sub-option is passed.
*(volatile int*)0 = 42;
return 0;
}
}
if (strcmp(cmd, "mem") == 0) { cmd_mem(); return 0; }
if (strcmp(cmd, "time") == 0 || strcmp(cmd, "date") == 0) { cmd_time(); return 0; }
if (strcmp(cmd, "display") == 0 || strcmp(cmd, "gpu") == 0) { cmd_display(); return 0; }
if (strcmp(cmd, "surfbench") == 0) { cmd_surfbench(); return 0; }
if (strcmp(cmd, "volume") == 0) { cmd_volume(""); return 0; }
if (strncmp(cmd, "volume ", 7) == 0) { cmd_volume(cmd + 7); return 0; }
if (strcmp(cmd, "stats") == 0 || strcmp(cmd, "telemetry") == 0) { cmd_stats(); return 0; }
if (strcmp(cmd, "ps") == 0) { cmd_ps(); return 0; }
if (strncmp(cmd, "threads ", 8) == 0) { cmd_threads(cmd + 8); return 0; }
if (strncmp(cmd, "kill ", 5) == 0) { cmd_kill(cmd + 5); return 0; }
if (strcmp(cmd, "dir") == 0) { cmd_dir("."); return 0; }
if (strncmp(cmd, "dir ", 4) == 0) { cmd_dir(cmd + 4); return 0; }
if (strncmp(cmd, "cd ", 3) == 0) { if (set_cwd(cmd + 3) != 0) print("cd: failed\n"); return 0; }
if (strncmp(cmd, "del ", 4) == 0) { delete_file(cmd + 4); return 0; }
if (strncmp(cmd, "type ", 5) == 0) { cmd_type(cmd + 5); return 0; }
if (strncmp(cmd, "write ", 6) == 0) { cmd_write(cmd + 6); return 0; }
// Make a local copy of the command line so we can mutate it safely if needed
char modifiedCmd[MAX_CMD];
strncpy(modifiedCmd, cmd, sizeof(modifiedCmd) - 1);
modifiedCmd[sizeof(modifiedCmd) - 1] = '\0';
// Parse background indicator execution flag (&)
bool background = false;
size_t cmdLen = strlen(modifiedCmd);
if (cmdLen > 0 && modifiedCmd[cmdLen - 1] == '&') {
background = true;
modifiedCmd[cmdLen - 1] = '\0'; // Strip the ampersand
// Clean up any trailing whitespace left before the ampersand
cmdLen = strlen(modifiedCmd);
while (cmdLen > 0 && (modifiedCmd[cmdLen - 1] == ' ' || modifiedCmd[cmdLen - 1] == '\t')) {
modifiedCmd[cmdLen - 1] = '\0';
cmdLen--;
}
}
char program[MAX_CMD];
if (!extractProgramPath(modifiedCmd, program, sizeof(program))) return 0;
uint32_t hProc;
if (create_process(program, &hProc, modifiedCmd) == 0) {
if (background) {
// Background mode: Clean up the handle immediately and skip waiting.
print("[Launched in background, handle: ");
printUInt(hProc);
print("]\n");
SysCloseHandle(hProc);
} else {
// Foreground mode: Wait for completion and flush standard keyboard stream.
uint32_t waitStatus = waitForegroundProcess(hProc);
if (waitStatus != NTLSTATUS_SUCCESS) {
print("shell: wait failed: ");
printUInt(waitStatus);
print("\n");
}
print("Process exited with code: ");
int32_t exitCode;
SysGetProcessExitCode(hProc, &exitCode);
printInt(exitCode);
const char* exitName = processExitStatusName((uint32_t)exitCode);
if (exitName) {
print(" (0x");
printHex32((uint32_t)exitCode);
print(" ");
print(exitName);
print(")");
}
print("\n");
SysCloseHandle(hProc);
INPUT_KEY drainedKey;
while (NtlInputPollKeyboard(&drainedKey) == NTLSTATUS_SUCCESS) (void)NtlInputReadKey(&drainedKey);
}
} else {
print("shell: launch failed\n");
}
return 0;
}
// Runs the requested operation.
int main(void) {
const char* cmdline = SysGetPeb()->CommandLine.Data;
char lineBuf[MAX_CMD];
print("shell: command line: ");
print(cmdline);
print("\n");
print("shell: ready\n");
while (true) {
print(SHELL_PROMPT);
if (readLine(lineBuf, MAX_CMD)) continue;
char* cmd = trim(lineBuf);
shellHistoryAdd(cmd);
if (runCommand(cmd)) break;
}
print("shell: goodbye\n");
SysExitProcess(0);
return 0;
}