add a realtime scheduler class and priority-inheritance mutexes with timeouts and abandonment, add an HDA audio driver and a SYS_AUDIO_* syscall family, flesh out kernel32 with Win32 threads, events, mutexes, critical sections, and condition variables, add SYS_RESUME_THREAD for suspended thread creation, add KeInitializeMemoryTypes to reprogram MTRRs and install a canonical PAT for WB/WC/UC control, rework the display pipeline with a pitched present path and console output flush, bring back disk.vhd with mtools since vvfat fucking sucks, harden AHCI with serialized cache flush, USB mass storage with SCSI sense-data decoding, and xHCI with cleaner DMA teardown, fix the last stray for(;;) in HalStopProcessor to while(true), pile on smoke tests for audio, win32 sync primitives, and thread suspend, implement AHCI timeout, kill readahead since it was desperetaly trying to murder me, fix doom sound x2.

This commit is contained in:
maksw committed 2026-08-11 18:38:36 +02:00
1 parent 8b254f84f4
commit 4add6789ba
177 files changed
+22565 -3070

No files matched your search

+550 -149
View File
@@ -12,6 +12,12 @@
#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) { SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromCstr(s) }; SysWriteConsole(&req); }
@@ -192,6 +198,20 @@ static void printStringWidth(const char* s, size_t width) {
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",
@@ -201,6 +221,7 @@ static const char* const gShellBuiltinCommands[] = {
"dir",
"display",
"exit",
"fbbench",
"gpu",
"help",
"kill",
@@ -211,6 +232,7 @@ static const char* const gShellBuiltinCommands[] = {
"threads",
"time",
"type",
"volume",
"write",
};
@@ -280,23 +302,112 @@ static void shellHistoryAdd(const char* cmd) {
gHistoryCount++;
}
// Replaces the visible line while keeping the cursor at the end.
static void shellEditorReplaceLine(char* buf, int len, int* pos, const char* text) {
int oldPos = *pos;
for (int i = 0; i < oldPos; i++) print("\b");
for (int i = 0; i < oldPos; i++) print(" ");
for (int i = 0; i < oldPos; i++) print("\b");
// Restores the character underneath the visible edit cursor.
static void shellEditorHideVisibleCursor(SHELL_VISIBLE_CURSOR* cursor) {
if (!cursor || !cursor->Visible) return;
int newPos = 0;
if (text) {
while (text[newPos] && newPos < len - 1) {
buf[newPos] = text[newPos];
newPos++;
(void)SysPutScreenChar(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);
SYS_CONSOLE_INFO info;
if (SysGetConsoleInfo(&info) != NTLSTATUS_SUCCESS) return;
char character = editor->Cursor < editor->Length
? editor->Buffer[editor->Cursor]
: ' ';
if (SysPutScreenChar(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++;
}
}
buf[newPos] = '\0';
*pos = newPos;
print(buf);
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.
@@ -340,23 +451,6 @@ static void shellUpdateCommonPrefix(char* common, size_t commonSize, const char*
common[i] = '\0';
}
// Appends text to the edited line and echoes it.
static bool shellEditorAppend(char* buf, int len, int* pos, const char* text) {
if (!buf || len <= 0 || !pos || !text) return false;
bool changed = false;
while (*text && *pos < len - 1) {
buf[*pos] = *text;
(*pos)++;
buf[*pos] = '\0';
char echo[2] = { *text, '\0' };
print(echo);
text++;
changed = true;
}
return changed;
}
// Prints one completion candidate.
static void shellPrintCompletionCandidate(const char* name, bool directory) {
print(" ");
@@ -454,18 +548,23 @@ static void shellCollectPathCompletions(const char* token, size_t tokenLength,
}
// Redraws the prompt and current edit buffer after a completion list.
static void shellRedrawPromptAndLine(const char* buf) {
static void shellRedrawPromptAndLine(SHELL_EDITOR* editor) {
print(SHELL_PROMPT);
print(buf ? buf : "");
if (!editor) return;
print(editor->Buffer);
shellEditorMoveLeftCells(editor->Length - editor->Cursor);
}
// Completes the token at the end of the current line.
static void shellCompleteLine(char* buf, int len, int* pos) {
if (!buf || len <= 0 || !pos || *pos < 0) return;
// 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;
size_t cursor = (size_t)*pos;
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;
@@ -490,14 +589,20 @@ static void shellCompleteLine(char* buf, int len, int* pos) {
size_t commonLength = strlen(state.Common);
bool expanded = commonLength > namePrefixLength;
if (expanded) {
shellEditorAppend(buf, len, pos, state.Common + namePrefixLength);
(void)shellEditorReplaceRange(editor, editor->Cursor, (int)tokenEnd,
state.Common + namePrefixLength);
}
if (state.MatchCount == 1) {
if (state.LastIsDirectory) {
if (*pos < len - 1 && *pos > 0 && !shellIsPathSeparator(buf[*pos - 1])) shellEditorAppend(buf, len, pos, "/");
if (editor->Cursor < editor->Capacity - 1 && editor->Cursor > 0 &&
!shellIsPathSeparator(buf[editor->Cursor - 1]))
(void)shellEditorInsert(editor, "/");
} else if (state.LastAddsSpace) {
if (*pos < len - 1 && (*pos == 0 || buf[*pos - 1] != ' ')) shellEditorAppend(buf, len, pos, " ");
if (editor->Cursor < editor->Capacity - 1 &&
(editor->Cursor == editor->Length ||
!shellIsTokenSeparator(buf[editor->Cursor])))
(void)shellEditorInsert(editor, " ");
}
return;
}
@@ -509,17 +614,27 @@ static void shellCompleteLine(char* buf, int len, int* pos) {
shellCollectBuiltinCompletions(token, tokenLength, NULL, true);
}
shellCollectPathCompletions(token, tokenLength, NULL, true);
shellRedrawPromptAndLine(buf);
shellRedrawPromptAndLine(editor);
}
// Reads one editable command line from the keyboard.
static bool readLine(char* buf, int len) {
int pos = 0;
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;
SYS_INPUT_EVENT_REQUEST inputReq;
inputReq.Size = sizeof(inputReq);
@@ -527,7 +642,9 @@ static bool readLine(char* buf, int len) {
inputReq.Flags = SYS_INPUT_EVENT_FLAG_NONE;
inputReq.TimeoutMilliseconds = SYS_WAIT_TIMEOUT_INFINITE;
inputReq.RecordOut = &input;
if (SysReadInputEvent(&inputReq) != NTLSTATUS_SUCCESS) { SysYield(); continue; }
KSTATUS inputStatus = SysReadInputEvent(&inputReq);
shellEditorHideVisibleCursor(&visibleCursor);
if (inputStatus != NTLSTATUS_SUCCESS) { SysYield(); continue; }
INPUT_KEY key = input.Key;
if (key == INPUT_KEY_NONE) { SysYield(); continue; }
@@ -545,18 +662,45 @@ static bool readLine(char* buf, int len) {
}
if (key == INPUT_KEY_BACKSPACE) {
if (pos > 0) {
pos--;
buf[pos] = '\0';
print("\b \b");
}
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(buf, len, &pos, gHistory[historyCursor]);
shellEditorReplaceLine(&editor, gHistory[historyCursor]);
}
continue;
}
@@ -564,25 +708,21 @@ static bool readLine(char* buf, int len) {
if (key == INPUT_KEY_DOWN) {
if (historyCursor < gHistoryCount) {
historyCursor++;
shellEditorReplaceLine(buf, len, &pos,
historyCursor < gHistoryCount ? gHistory[historyCursor] : "");
shellEditorReplaceLine(&editor,
historyCursor < gHistoryCount ? gHistory[historyCursor] : historyDraft);
}
continue;
}
if (key == INPUT_KEY_TAB) {
shellCompleteLine(buf, len, &pos);
shellCompleteLine(&editor);
continue;
}
char c = input.Char ? input.Char : shellKeyToChar(key, modifiers);
if (c < 0x20 || c == 127) continue;
if (pos < len - 1) {
buf[pos++] = c;
buf[pos] = '\0';
char echo[2] = { c, '\0' };
print(echo);
}
char text[2] = { c, '\0' };
(void)shellEditorInsert(&editor, text);
}
return false;
@@ -604,6 +744,7 @@ static void cmd_help() {
" mem - Show memory usage\n"
" time - Show system wall-clock time\n"
" display - Show display provider and counters\n"
" fbbench - Benchmark Doom-size and full-screen presents\n"
" stats - Show scheduler/CPU/MM telemetry\n"
" ps - List processes\n"
" threads <pid> - Show one process's thread statuses\n"
@@ -611,6 +752,9 @@ static void cmd_help() {
" 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"
@@ -639,6 +783,117 @@ static void printCpuFlags(uint32_t flags) {
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;
@@ -801,6 +1056,12 @@ static void cmd_stats(void) {
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");
@@ -975,20 +1236,6 @@ static void cmd_stats(void) {
print(" standby="); printUInt64(fileCache.StandbyTransitions);
print(" standby-hits="); printUInt64(fileCache.StandbyHits);
print(" drop-fail="); printUInt64(fileCache.DropFailures); print("\n");
print(" read-ahead: requests="); printUInt64(fileCache.ReadAheadRequests);
print(" requested="); printUInt64(fileCache.ReadAheadPagesRequested);
print(" queued="); printUInt64(fileCache.ReadAheadPagesQueued);
print(" loaded="); printUInt64(fileCache.ReadAheadPagesLoaded);
print(" skipped="); printUInt64(fileCache.ReadAheadPagesSkipped);
print(" fail="); printUInt64(fileCache.ReadAheadFailures);
print(" throttled="); printUInt64(fileCache.ReadAheadPagesThrottled); print("\n");
print(" read-ahead max: pages/request="); printUInt64(fileCache.MaxReadAheadPagesPerRequest); print("\n");
print(" batch fills: reads="); printUInt64(fileCache.BatchReads);
print(" requested="); printUInt64(fileCache.BatchPagesRequested);
print(" loaded="); printUInt64(fileCache.BatchPagesLoaded);
print(" max-request="); printUInt64(fileCache.MaxBatchPagesRequested);
print(" max-loaded="); printUInt64(fileCache.MaxBatchPagesLoaded); print("\n");
print("Filesystem:\n");
print(" path cache: lookups="); printUInt64(filesystem.PathLookups);
print(" hits="); printUInt64(filesystem.PathCacheHits);
@@ -1012,18 +1259,6 @@ static void cmd_stats(void) {
print(" writes: requests="); printUInt64(disk.WriteRequests);
print(" sectors="); printUInt64(disk.WriteSectors);
print(" max-sectors="); printUInt64(disk.MaxWriteSectors); print("\n");
print(" read-ahead: hits="); printUInt64(disk.ReadaheadHits);
print(" misses="); printUInt64(disk.ReadaheadMisses);
print(" stores="); printUInt64(disk.ReadaheadStores);
print(" sectors="); printUInt64(disk.ReadaheadSectorsLoaded);
print(" max-sectors="); printUInt64(disk.MaxReadaheadSectors); print("\n");
print(" read-ahead misc: served-bytes="); printUInt64(disk.ReadaheadBytesServed);
print(" seq="); printUInt64(disk.ReadaheadSequentialDetections);
print(" invalidations="); printUInt64(disk.ReadaheadInvalidations);
print(" suppressed="); printUInt64(disk.ReadaheadSuppressed);
print(" alloc-fail="); printUInt64(disk.ReadaheadAllocFailures);
print(" read-fail="); printUInt64(disk.ReadaheadReadFailures); print("\n");
print("Surfaces:\n");
print(" lifetime: created="); printUInt64(surface.CreatedSurfaces);
print(" destroyed="); printUInt64(surface.DestroyedSurfaces);
@@ -1123,9 +1358,11 @@ static void printDisplayStats(const char* title, const DISPLAY_STATS* st) {
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("\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: "); printUInt64(st->BytesCopied); 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);
@@ -1149,10 +1386,205 @@ static void cmd_display(void) {
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 ExpectedBytes;
uint64_t ScanoutBytes;
uint64_t DirectPresents;
} 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-present 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, &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; i++) {
status = SysPresentSurface(surface, &rect, 1);
if (status != NTLSTATUS_SUCCESS)
break;
}
SYS_DISPLAY_INFO before;
SYS_DISPLAY_INFO after;
memset(&before, 0, sizeof(before));
memset(&after, 0, sizeof(after));
if (status == NTLSTATUS_SUCCESS)
status = SysQueryDisplayInfo(&before);
uint64_t begin = 0;
uint64_t end = 0;
uint32_t completed = 0;
if (status == NTLSTATUS_SUCCESS) {
begin = SysGetTick();
for (; completed < frames; completed++) {
status = SysPresentSurface(surface, &rect, 1);
if (status != NTLSTATUS_SUCCESS)
break;
}
end = SysGetTick();
uint32_t queryStatus = SysQueryDisplayInfo(&after);
if (status == NTLSTATUS_SUCCESS && queryStatus != NTLSTATUS_SUCCESS)
status = queryStatus;
}
result->Frames = completed;
result->Status = status;
result->ElapsedTicks = end - begin;
result->ExpectedBytes = (uint64_t)width * (uint64_t)height * sizeof(uint32_t) * completed;
if (after.DeviceStats.ScanoutBytes >= before.DeviceStats.ScanoutBytes)
result->ScanoutBytes = after.DeviceStats.ScanoutBytes - before.DeviceStats.ScanoutBytes;
if (after.DeviceStats.DirectPresentCount >= before.DeviceStats.DirectPresentCount)
result->DirectPresents = after.DeviceStats.DirectPresentCount - before.DeviceStats.DirectPresentCount;
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 bytes = result->ScanoutBytes ? result->ScanoutBytes : result->ExpectedBytes;
uint64_t mibTenths = shellRatioTenths(bytes * 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(" scanout="); printUInt64(mibTenths / 10u); print("."); printUInt64(mibTenths % 10u); print(" MiB/s");
print(" direct="); printUInt64(result->DirectPresents);
print(" bytes="); printUInt64(bytes);
print("\n");
}
// Benchmarks the synchronous surface-to-scanout path without console traffic.
static void cmd_fbbench(void) {
SYS_DISPLAY_INFO info;
uint32_t status = SysQueryDisplayInfo(&info);
if (status != NTLSTATUS_SUCCESS) {
print("fbbench: display query failed status=0x"); printHex32(status); print("\n");
return;
}
uint64_t frequency = 0;
status = SysGetTickFrequency(&frequency);
if (status != NTLSTATUS_SUCCESS || !frequency) {
print("fbbench: 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("fbbench: running; the framebuffer will be overwritten temporarily\n");
SHELL_FB_BENCH_RESULT doom;
SHELL_FB_BENCH_RESULT full;
shellRunFramebufferBenchmark(doomWidth, doomHeight, doomFrames, frequency, &doom);
shellRunFramebufferBenchmark(fullWidth, fullHeight, fullFrames, frequency, &full);
SysClearScreen(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;
@@ -1200,6 +1632,7 @@ static const char* threadStateName(uint32_t state) {
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 "?";
}
}
@@ -1331,7 +1764,7 @@ static void cmd_threads(const char* args) {
print(" (Count: ");
printUInt((uint32_t)count);
print("):\n");
print(" TID State Pri CPU LastCPU QRem QTick Burst Wait WStat Flags\n");
print(" TID State Base Eff CPU LastCPU QRem QTick Burst Wait WStat Flags\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;
@@ -1342,7 +1775,11 @@ static void cmd_threads(const char* args) {
print(" ");
printStringWidth(threadStateName(t->State), 5);
print(" ");
printUIntWidth(t->Priority, 3);
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);
@@ -1431,7 +1868,7 @@ static int shellCompareNames(const char* a, const char* b) {
if (!a) a = "";
if (!b) b = "";
for (;;) {
while (true) {
char ca = shellAsciiLower(a[i]);
char cb = shellAsciiLower(b[i]);
if (ca != cb)
@@ -1540,7 +1977,7 @@ static void cmd_dir(const char* path) {
uint32_t count = 0;
uint32_t capacity = 0;
for (;;) {
while (true) {
SYS_DIR_ENTRY ke;
st = SysReadDir(hDir, &ke);
if (st != 0)
@@ -1575,7 +2012,7 @@ 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;
for (;;) {
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);
@@ -1604,78 +2041,39 @@ static bool extractProgramPath(const char* cmdline, char* out, size_t outSize) {
return pos != 0;
}
// Consumes queued Ctrl-C input without taking ordinary foreground stdin.
static bool shellConsumeQueuedCtrlC(void) {
for (int i = 0; i < 4; i++) {
INPUT_KEY_RECORD input;
SYS_INPUT_EVENT_REQUEST inputReq;
inputReq.Size = sizeof(inputReq);
inputReq.QueueHandle = 0;
inputReq.Flags = SYS_INPUT_EVENT_FLAG_NONE;
inputReq.TimeoutMilliseconds = 0;
inputReq.RecordOut = &input;
if (SysPeekInputEvent(&inputReq) != NTLSTATUS_SUCCESS) return false;
if ((input.Modifiers & INPUT_MOD_CTRL) && input.Key == INPUT_KEY_C) {
(void)SysReadInputEvent(&inputReq);
return true;
}
if (input.Key == INPUT_KEY_LEFT_CTRL || input.Key == INPUT_KEY_RIGHT_CTRL) {
(void)SysReadInputEvent(&inputReq);
continue;
}
return false;
}
return false;
}
// Returns whether one input key is currently held.
static bool shellIsKeyDown(INPUT_KEY key) {
bool down = false;
return SysIsKeyDown(key, &down) == NTLSTATUS_SUCCESS && down;
}
// Waits for a foreground process while watching Ctrl-C without stealing ordinary stdin.
// Waits for a foreground process while polling Ctrl-C without consuming child input.
static uint32_t waitForegroundProcess(uint32_t hProc) {
bool sentBreak = false;
uint32_t inputQueue = 0;
if (SysOpenInputQueue(0, &inputQueue) != 0)
return SysWait(hProc, SYS_WAIT_FLAG_NONE);
uint32_t handles[2] = { hProc, inputQueue };
uint32_t index = 0;
SYS_WAIT_MANY_REQUEST waitReq;
waitReq.Size = sizeof(waitReq);
waitReq.Flags = SYS_WAIT_FLAG_NONE;
waitReq.Handles = handles;
waitReq.Count = 2;
waitReq.SignaledIndexOut = &index;
waitReq.TimeoutMilliseconds = SYS_WAIT_TIMEOUT_INFINITE;
for (;;) {
index = 0;
uint32_t status = SysWaitMany(&waitReq);
if (status != NTLSTATUS_SUCCESS) {
SysCloseHandle(inputQueue);
while (true) {
uint32_t status = SysWaitSingle(hProc,
SYS_WAIT_FLAG_NONE,
SHELL_FOREGROUND_POLL_MS);
if (status == NTLSTATUS_SUCCESS)
return status;
}
if (index == 0) {
SysCloseHandle(inputQueue);
if (status != NTLSTATUS_TIMEOUT)
return status;
}
uint32_t modifiers = SysGetKeyModifiers();
if (((modifiers & INPUT_MOD_CTRL) && shellIsKeyDown(INPUT_KEY_C)) || shellConsumeQueuedCtrlC()) {
if (!sentBreak) {
print("^C\n");
(void)SysKillProcess(hProc, (int32_t)NTLSTATUS_PROCESS_KILLED);
sentBreak = true;
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;
}
}
}
@@ -1727,6 +2125,9 @@ static int runCommand(const char* cmd) {
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, "fbbench") == 0) { cmd_fbbench(); 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; }