Repository navigation
Conversation
…s logo never is screen_loader_lines was red on main's nightlies 36550208853 (7e15181) and 36696295750 (ace064f), and on the branch nightlies 36600425263 and 36709239346, every time with the same numbers: the panel carried 26 rows at the GOP query and 41 at the loader's last line, a growth of 15, where the loader printed 14 lines between them, 14 rows at 240 columns It was green on 36400924827 (main a7cd327) and 36496779560, both "26 to 42, for 16 line(s) printed". The loader is not at fault: a growth of fifteen is a panel that kept drawing. The instrument is. OVMF's PlatformBootManagerAfterConsole draws the TianoCore logo after the console's last ClearScreen (edk2 BootLogoEnableLogo: Logo.bmp, 193x58, centred, so x 863..1055 and y 511..568 on the 1920x1080 panel), and the graphics console then draws its 8x19 cells from the top-left corner, overwriting only the cells a line reaches. text_row_bands scanned the whole width: a row printed short over the logo joined it into one band taller than the pitch and was dropped, and a row printed across the logo's columns, 107 to 131, wiped the logo out of its own cell row, freeing the rows beside it. The GOP line lands on row 26 (y 502..520), the logo's first. At the GOP query the logo is whole beneath it and the GOP row is dropped with it: 26 counted for 27 printed. 1090cf6 (#583) removed the loader's 128-column "RTC zone" line, so the 165-column "Black box" line now lands on row 27 and wipes the logo there; at the last line the GOP row counts again, and the growth is one more than the lines printed. Before it, the RTC line stopped four cells short of the logo's right edge, the remnant kept rows 26 and 27 joined, and the root bridges' 410-column dump (26ad88c, the same PR) gave two rows of slack. The oracle is edk2's own source: GraphicsConsole.c (the text origin, whole cells blitted, the wrap), LaffStd.c (the 8x19 font), BootLogoLib.c with Logo.c and Logo.bmp (the logo and its place, and the cursor it turns off), modelled and fed the nightlies' console lines, then counted by text_row_bands. It gives 26 and 41 for the red lines and 26 and 42 for the green ones, every number recorded; without the logo it gives 27, 41 and 44, none of them. Taking the RTC line alone out of the green console turns it red (26 to 43 for 15 lines on 16 rows); taking the root-bridge line alone out leaves it green. - text_row_bands reads the panel's first EDGE_CELLS cells only: every console row starts there, and a logo centred on the panel is not there. The same model counts 27, 41, 27 and 44 there, the rows printed each time. - The test boots once, to the loader's last line, and holds the panel to exactly the rows the console printed since the firmware's last ESC[2J; screen::edge_rows computes them by the same edge rule. The GOP-query dump goes: an equality needs no baseline, and that dump raced the loader, which goes on printing while it is taken (the 23 against 24 rows recorded in issues/build/parallel-tests-red-under-other-suites.md). A panel the query stopped carries the rows up to the query and no more, and the red names that number beside the one it wanted. - firmware_rows_at_the_edge, a harness check, stages a panel in edk2's geometry with a centred block that a long row cuts and two short rows join, and holds text_row_bands and edge_rows to its 15 rows. Counted across the whole width it is 13: that mutation of text_row_bands reds it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
The orchestrator's guest runs of efc6e0c went red with "the panel carries 0 band(s) of lit scanlines" three times out of three: alone, under the exclusive-GOP control, and in the whole suite. The first 8 cells of the panel were dark because the firmware this host boots does not draw its text there. What the panel holds depends on the firmware. edk2's graphics console centres its text mode on the panel (InitializeGraphicsConsoleTextMode's DeltaX and DeltaY), wraps a line when its row is full, and scrolls the text area once the cursor passes the last row (GraphicsConsoleConOutOutputString). Which mode it draws in is the firmware build's choice: - CI boots Debian's ovmf-generic, which draws in 240x56: text from x=0 and y=8, and the loader's 41 rows fit without scrolling. - The dev host boots Homebrew QEMU 11.1.1's own edk2-x86_64-code.fd, which draws in 80x50: text from x=640 and y=65. At 80 columns the console fills 58 rows, so the panel scrolls and keeps the last 49. These modes were not read off a screendump. They come from an edk2 pixel model: that source's cells, wrap, scroll and Logo.bmp, fed the red nightly's console and counted with main's whole-width counter. In 80x50 it counts 37 rows at the GOP query and 47 at the last line, which are main's local passes exactly ("37 to 47"). In 240x56 it counts CI's 26 and 41. No other mode edk2 offers on a 1920x1080 panel gives either pair. 100x31, 128x40 and 160x42 have too few rows for 47, and 80x25 has too few for either. Only 80x50 starts its text past the first 8 cells. So the counter can no longer assume a margin, a column count or the absence of a scroll: - Ppm::firmware_text_mode picks the mode off the panel, out of the modes edk2 offers there (TextMode::offered). It must be the one whose first cell column holds the leftmost lit pixel, where every row starts. Its rows must also hold everything lit in its first 8 cells, and that is what separates 80x25 from 80x50. - Ppm::edge_rows reads each of that mode's rows in its first 8 cells, cell by cell. A glyph never leaves its cell, and a centred logo narrower than 512 pixels never reaches those cells. Bands, pitches and their refusals are gone. - TextMode::panel is the same row read off the console: each line since the last ESC[2J, wrapped at the mode's columns. A line that fills its last row leaves a blank row after it. The text scrolls on a line feed at the last row. - The test requires the two to agree row by row, and prints both maps and their counts when they do not. The GOP line's width no longer decides the columns. The exclusive-GOP control now reaches this judgement: its panel stops before the GOP line while the model expects every row. firmware_rows_at_the_edge stages both real geometries with a pixel-level edk2 renderer: cells blitted whole over a centred 193x58 logo, wrap, and a scroll that moves the text area's pixels. It checks the mode found and the rows against counts derived by hand: 46 lit rows in 80x50 after four scrolled-off rows, and 48 in 240x56. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
`cargo run -- --ci host` went red at 92d4b11 on one step, clippy's manual_is_multiple_of in TextMode::printed. This spells it the way clippy asks. 92d4b11's message gets two sentences wrong: - "Only 80x50 starts its text past the first 8 cells" is false. Every mode edk2 offers on a 1920x1080 panel except 240x56 starts past them. What singles out 80x50 is the row counts, as the sentences before it say. - Main's local passes were not matched "exactly". They counted 37 or 38 rows at the GOP query and 47 at the last line. The model counts 37 and 47 when fed the CI console, which is not the console those local boots printed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
Reverts 51e64b3 and deletes the issue 45db225 filed for it, issues/build/screen-loader-lines-counts-one-row-more-than-the-loader-printed.md. The red was not a flake: the counter read OVMF's boot logo as text rows, the cause since #583, and #640 corrects the count. The test stays with this branch's rule as a red that is fixed rather than deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
|
Orchestrator runs at 382919c (
|
|
Review round 1, head Net lines: +282 −130 = +152. The harness and guest test ( The brief's questions
BLOCKER
NOTE
REMOVE
SEND BACK |
The one screendump was taken as the loader's last line reached the serial. uefi-services' println! sends that line's CRLF as its own OutputString, and edk2's graphics console scrolls on it when the cursor is on the last row, so a ConSplitter that writes the terminal before the graphics console lets the dump land before the scroll, one row off everywhere. The review asked for a dump after a later event; the kernel's first 16550 record is not one: arm() commits `panic console: armed` and repaints the whole panel before serial::init makes the 16550 a backend, so every dump after that record would meet the repaint refusal. The test now dumps the panel back to back until two dumps carry the same text mode and row map, and judges that map. A dump the kernel has repainted is refused as before; a panel still changing when a 30-second liveness ceiling (budget-scaled) passes fails with both maps. Review notes: - firmware_rows_at_the_edge stages, in both modes, the exclusive-GOP control's panel: one that stopped after the 45 short lines. It must be read in the staged mode and must not carry the console's rows. - The CSI stripper goes: after the last ESC[2J the only sequence is the leading cursor-home, which changes no row in either measured console. - TextMode::printed is folded into TextMode::panel. Its one other reader was the success line's "N of them after the GOP query", which no judge reads and which goes with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
|
Orchestrator runs at 6e0d7da (logs
Nightly at this head: https://github.com/ToyOSOrg/ToyOS/actions/runs/36763711317 (queued behind 36760010132 at 382919c, whose twelve guest shards all passed). |
|
Review round 2, head Round 1 BLOCKERs
The brief's questions
Net lines: +292 −129 = +163. Production 0, tests +163. The cut deletes about 150 of main's lines instead. BLOCKER
REMOVE
SEND BACK |
…es what it guarded Red on main's nightly 36696295750 at `ace064f9d`, `guest (8)`: "the panel carried 26 rows at the GOP query and 41 at the loader's last line, a growth of 15, where the loader printed 14 lines between them, 14 rows at 240 columns". A red test is fixed or deleted. #640's count has run on no nightly, and the behaviour the test guarded, `query_gop` opening `GraphicsOutput` without EXCLUSIVE, #660 refuses at compile time: `clippy.toml` disallows `open_protocol_exclusive`, and the loader's exclusive opens are bounded by `Exclusive`, which `GraphicsOutput` does not implement. This reverts `cb9a8d848`'s code: the registration and its comment, the screen arm, `Ppm::text_row_bands`, and `bootlog::LOADER_GOP_LINE` with its row in the loader-lines gate, which only it read. `loaderlog::GOP_AT` stays: the loader prints it. Reverting this commit restores the test. `cargo test --test toyos-build --no-run`: exit 0, no warning. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
`issues/build/nothing-refuses-the-loader-an-exclusive-gop-open.md` records `212516e71` and its revert, the nightly red it was deleted on, and #660 as the landing that refuses an exclusive open of `GraphicsOutput` at build time, with that refusal as its exit. `parallel-tests-red-under-other-suites` loses "`screen_loader_lines` is #640's to fix" and points at it. `212516e71`'s message says #640's count has run on no nightly. It has: the nightly 36763711317 at #640's head `6e0d7da82` passed `screen_loader_lines` in `guest (10)`, which the new issue says. The test is deleted rather than fixed because #640 is superseded by #660's guard. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
Aims to fix the
screen_loader_linesred on main. The loader is correct. The test's row counter was counting the firmware's boot logo.Unproven until a nightly shows it. The setup that went red is CI's KVM with Debian OVMF in 240x56. That claim holds only once
gh workflow run nightly.yml --ref wt/toyos-loaderlinesruns with its headSha equal to this PR's head. On the shard that runs the test, its log must carry these two lines, in this order:The review quoted the first line with
, 14 of them after the GOP queryat the end. This head drops that clause (see the fix below), so the line above is what the test prints now. Any mode other than 240x56 makes the root-cause table below wrong, even on a green run.Root cause
The red. Main's nightlies 36550208853 (
7e151819e) and 36696295750 (ace064f9d, guest shard 8) were red, and so were the branch nightlies 36600425263 and 36709239346. All four gave the same numbers:The last green runs were 36400924827 (main
a7cd32765, shard 4) and 36496779560 (shard 6). Both printedthe panel grew 16 row(s) across the GOP query, 26 to 42, for 16 line(s) printed. The only loader change betweena7cd32765and7e151819eis #583.The mechanism. OVMF draws the TianoCore logo (
BootLogoEnableLogo, which also turns the cursor off) after the console's lastClearScreen. The logo isLogo.bmp, 193x58 pixels, centred on the panel. The graphics console then draws its 8x19 cells, and it overwrites only the cells a line reaches. Main'stext_row_bandscounted bands of lit scanlines across the whole width, and the logo broke that count in two ways:1090cf6ea(in #583) removed the loader's 128-columnRTC zoneline. Since then the 165-columnBlack boxline lands on the logo's second row and erases it there, so at the last line the GOP row counts again and the growth comes out one more than the lines printed. The model below reproduces all of these numbers.The firmware's text mode differs by host
Round 1 read the panel's first 8 cells from x=0. On the dev host that found no lit pixel at all: the orchestrator's runs of
efc6e0c21were red three times out of three withthe panel carries 0 band(s) of lit scanlines, alone, under the exclusive-GOP control, and in the whole suite.The reason is that edk2's graphics console centres its text mode on the panel (
InitializeGraphicsConsoleTextMode'sDeltaXandDeltaY). It wraps a line when its row is full and scrolls the text area once the cursor passes the last row (GraphicsConsoleConOutOutputString). Which mode it draws in is the firmware build's choice:ovmf-genericedk2-x86_64-code.fdWhere these modes come from. CI's serial names its mode. Nightly 36696295750, job 109873180506, carries the terminal's
ESC[8;056;240tbefore its lastESC[2J. The dev host's mode comes from a pixel model built from edk2's source (GraphicsConsole.c,LaffStd.c,BootLogoLib.c,Logo.bmp): its cells, wrap and scroll, fed the red nightly's console and counted with main's whole-width counter. For every mode edk2 offers on a 1920x1080 panel, the model's counts at the GOP query and at the last line are:37 to 47(5 runs) and38 to 47(8 runs). Only 80x50 comes close. Its 37 and 47 come from the CI console, which is not the console those local boots printed, so it matches them closely, not exactly.The fix
Ppm::firmware_text_modereads the mode off the panel. It picks from the modes edk2 offers there (TextMode::offered: UEFI's 80x25 and 80x50,mGraphicsConsoleModeData, and the whole panel).Ppm::edge_rowsreads each of that mode's rows in its first 8 cells, cell by cell. A glyph never leaves its cell. A centred logo narrower than 512 pixels never reaches those cells in any mode 80 or more columns wide. Bands, the median pitch and their refusals are gone.TextMode::panelreads the same rows off the console. It takes every line since the lastESC[2Jas it came off the serial and wraps it at the mode's columns. A line that fills its last row leaves a blank row after it, which is edk2's wrap followed by the line's own CRLF. A line feed on the last row scrolls the text. The review's note hadTextMode::printedfolded into it.printed's one other reader was the success line'sN of them after the GOP query, which no judge reads, so that clause is gone too.ESC[2Jthe only sequence is the leading cursor-home. The review measured that it changes no row on either console. At 240 columns it lengthens the first line from 116 to 126 columns, still one row. At 80 the line takes 2 rows either way, and both scroll off.println!sends a line's CRLF as its ownOutputString, and edk2 scrolls on that line feed at the last row. If ConSplitter writes the terminal before the graphics console, the serial line is complete before the panel has scrolled. The test therefore dumps the panel back to back, with no delay, until two consecutive dumps carry the same text mode and row map, and judges that map.qemu.budget(30 s), a liveness ceiling only. If the panel is still changing when it passes, the test fails and prints both dumps' maps.screendumpdirectly.screendump_whiletakes anFnpredicate and returns only the last dump, so carrying the previous map through it would need aRefCell.[kernelline on the 16550.panic_console::armcommitspanic console: armedand repaints the whole panel beforeserial::initmakes the 16550 a backend. Every dump after that line would meet the refusal. Job 108841154205's serial shows that record as the first kernel line, right afterLoader log: the kernel handoff begins.firmware_rows_at_the_edgestages both real geometries with a pixel-level edk2 renderer: cells blitted whole over a centred 193x58 logo, wrapping, and a scroll that moves the text area's pixels, logo included. In each mode it requires:Gates
All at
6e0d7da82.cargo test --test toyos-checks -- firmware_rows_at_the_edge screen_decodercargo test --no-run --test toyos-buildcargo run -- --ci host[ci] Host: 55 step(s), all green,checks::firmware_rows_at_the_edge ... okexclusive-gop.patchapplied, thencargo run -- --build-onlyMutations of the judge and of the control, each applied as a checked patch, built, run and reverted. Every mutant built (
cargo test --no-run --test toyos-checks, EXIT=0). Each was then run withcargo test --test toyos-checks -- firmware_rows_at_the_edge, and each went red:TextMode::panelfirmware_text_modeThe first five mutants fail on the 80x50 case before the 240x56 case runs. The last two show that the control fires in each mode on its own.
Unsure
panic_console::arm, just after ExitBootServices. Main's single dump after the loader's last line fitted in that window on CI's KVM: the red nightlies counted 41 rows there and did not refuse. Nobody has measured whether two dumps fit. If they do not, the test goes red with the repaint refusal and the kernel's decoded screen, not green.firmware_text_modecannot read fails at once rather than being dumped again.TextMode::offeredcopies edk2's mode table. A firmware that draws in a mode outside it is refused by name rather than counted.🤖 Generated with Claude Code
https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L