From 32e4c2e5da0e85a15d71da8db859aad43147e552 Mon Sep 17 00:00:00 2001 From: vhaudiquet Date: Sat, 29 Aug 2026 23:46:21 +0200 Subject: [PATCH] stub: render failure diagnostics as bit-bands on the panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Round 6: pa==0 accepted but parse still fails on device (5 blinks). All local reproductions pass, so the remaining unknowns are the actual runtime values. Since the scanout address is known without any parse (DRAM address 0 — Round 5), fail_dump() now renders diagnostic words as 32 white/black bit-cells per row directly into the scanout buffer after the 5-blink execution signal. Marker 0xC0DE0001: find_coreboot_reg failed — dumps x0 + raw DTB header. Marker 0xC0DE0002|rc: find_framebuffer failed — dumps LBIO addr/size, raw table magic/header_bytes/entries, and raw words at +24..+68. Also fix a build break: u32 array = {0} emitted memset in freestanding. host_test and qemu_test pass; payload e619166a... flashed and verified. --- RESEARCH.md | 30 ++++++++++++ krane-fb-stub-payload.bin | Bin 159744 -> 159744 bytes krane-fb-stub.bin | Bin 18448 -> 18832 bytes main.c | 94 +++++++++++++++++++++++++++++++------- 4 files changed, 108 insertions(+), 16 deletions(-) diff --git a/RESEARCH.md b/RESEARCH.md index 5d2ccee..984e8e7 100644 --- a/RESEARCH.md +++ b/RESEARCH.md @@ -321,6 +321,36 @@ writes are kept but are now believed to be redundant on this firmware. Payload `b25d9132…` flashed (cmp + vbutil OK). host_test gained a pa==0 regression test; qemu_test unchanged (its synthetic record uses pa!=0). +## Round 6 — pa==0 accepted but parse STILL fails: bit-band diagnostic dump + +Reboot with `b25d9132…` (pa==0 accepted): **5 blinks again** — parse_fail +persists, and with pa==0 accepted the failure is somewhere else in +find_coreboot_reg or find_framebuffer. Every local reproduction passes: +host_test parses the live fdt (21/21 checks incl. the new pa==0 test), +qemu end-to-end passes, and the runtime tree shape is provably identical +to the live fdt (same fixup code; krane DTB has no pre-existing /firmware +node; root cells 2/2). The remaining unknowns are the actual runtime +values — what is really at x0 and what the real LBIO bytes are. + +Key enabler: on failure the scanout address is KNOWN without any parse — +DRAM address 0 (Round 5; the visible menu erase proves the OVL scans it). +So the stub can render diagnostic data directly on the panel. + +### New failure path (payload `e619166a…`) + +`fail_dump()`: 5 blinks (execution proof, same signature), then paint a +bit-band dump into address 0: one row per u32, 32 cells of 32×32 px, MSB +first, white=1 / black=0, rows every 64 px. Word 0 = marker: + +- `0xC0DE0001` — find_coreboot_reg failed; words 1-2 = x0 pointer, + words 3-6 = raw DTB header (magic, totalsize, off_struct, off_strings, + off_mem_rsvmap). +- `0xC0DE0002 | rc` — find_framebuffer failed; words 1-3 = LBIO + addr/size, words 4-6 = raw table magic/header_bytes/entries, words 7-12 + = raw words at table+24..+68 (first record headers). + +User photographs the panel; values are decoded offline. + Recovery: power-cycle, boot USB (unchanged), `dd if=mmcblk0p1-pmos-backup.img of=/dev/mmcblk0p1 bs=4M conv=fsync`. diff --git a/krane-fb-stub-payload.bin b/krane-fb-stub-payload.bin index 59fd62f0a9a2ff79f097670026b080438b257e23..5218e333501d9404d3a16dad2835b019e12bd158 100644 GIT binary patch delta 2329 zcmah~3s6+o8UF8M*$1G@!vxJL3-YLdRun3mf}8?csf^0H7KbEV6m8HQAB)y8WaGU8 zBC=Fj(V)@7l~$`erAfwESi$hHGSQ&c-SIKTlttcxHnU1)6}Zrrj6h}OrDtVY6}b`A__AVmHAK*w=Hr&pfD6W! z=dLMZNx`Z=WZx;#JXyIb`ig(o>GUlDLt95?tKER(a<(3N*|F4V3_b0iygWJ4SULTV4@z2#;@zJvqr|kV{B`R`PMna1Sj6nW z4|knky#A2>*|n92Q??8h{Uj{mcJ{|f=gUfJ14A_B2Trc@i)(B;dhocSGH*##v)Z20 z{6Vq)J@4PREuJ`4`tB7kCf;n~;?IXx6^uTAaw*XM;bHsKMX4(`MW&UXiF>WV@_bV-cm?)Uq2aZ~)PhIs!wu6vP7`me4oZoU3>b3#kUo^NuVPE76l;M$_a+r6u@ zSKdpe$T8}2Zugyo^sShd&zFqwW2?tD492oojPr8N$IEYyR};DH2<4+nDFc8cpi&e^ z)zoWr@;|EM^ZnjhCo{Xkxp8xghk<&J9QNu@?{s-sca`%IBabOi z!>xMY^-&<`_l5Lvo(+Y92VyInn*k3&f{%pmpWh}5_$(F?CemGCxpD#~GF+elD>Z6y zX#u{>Q-U=N_d|gi`2r8-V=A0->W3P<{QqfiKNLx0!F=kaXi&73J0FP^htGoGk;{0! zue&wSF1C7PYm1$66mj%23i|-V>q{d$XOsdImV$Lg9;mFLTIO~S19lo{TSNvl8PQxj zngftoIe?KcoOiO2osaw7EW}f*UWtZ5paSLufK4&?7dBB)o2f}mI|@nTl_N)>InG=|OsYaImI_aVdDvytAQY|DMZ z1jO_(lud^J(=$kuf(Uw5o}l;T1wHm&)l?iD$V~zT2FV5o3KO6v2P%{HTl6*c&|v6e zXglh1c1c7cv|~z2)I`T=ps*J=1^7;2gN7v4;hL1seC)bb4VbfVFZ^EQ`1)si4xeTr zKoWb5aZASBv!xh`CoS-_gEz?3#4FB1((LGfPEAn8h3=p^4| zfyOLIy4?)wj)|P17TwgMa3=~c9TO96n1y&%Tkbg&+J|#qO&q7O41hz%%j|qGaqJJl z^~`d8J=R$}e6G+4U^;~c1T5Vd+^6#(+bE=(6}Z-cr8Q2Zn$KeC1fsPvXp%*q)Eh<( z2j*dHrn+Sq0oF7hn+Zrb)|xT(NOu$u?Z<{1#AYg{c)fr`H#U@XkQ*CHz{8|w63~$Q zEkq5X5mAenj~IdYE+RoRA!ZkyS16WH&x`G(3Vkgn{GE9sQM!lY= z?F=3;bQg4r-9$I^6`}>P8<8hE77rcj#d#^w4NR5ILG#%UgRuLz6CIQjUEe}*JamC> zXb^N?;GTN~bZ&9K9^XhN+D3{>kC7q{utr3SDN+y*XdsYQtSu_QdJ_w?8Z16<;8(-c zi#2wafK5srjUx=lgGsR_98p^DVdxlX?=G(W_c>{g!r}aWZ8pv&uC#U?*QB=`4&}G6 cI_YcGxJ*eE5Z2PLv99s6OsebI8A8wh56|PI761SM delta 1988 zcmb7EeN>az8Gr8k<`bg^1fi8dLcl8O5fqRVXRaWAfMpWjZVtx6=M;jp0j(ApZ?G^a zp(_zqY;7fQ3JAv?XKPE-kAYqFXm#y`L$U6-CZJGCbs8O#Li6r6suoB7?- zffs#`&jm!hH1X;)9T#(=Ooh4in@iuVUt3#nB>ipWhOmpA#SX$Re$@vYZ9k11uy)6Cw1$j`Tj^2Ol zqe}kZuQL8R>sT%uOPu=IWN{SK^(rR19-NLm^4x~HOREzt&%2L48MAw}=7Ya97yLFk z*cZ90vG(fn+7p+j=2x6p*U?8a3e*g@>E6iN2A?l8Wve{B`mQpLewAKjIL>6l-35m} z^(3eoO@mS1zrA}sckldtM;1P@n zfh5)cK}{AjNjsWj<%?ST(}_wcK}}gnbK2f_c91nBWUCs_5%?E~_}`y;YwK%-#3?lP zHURrD^nF1{GQ;2Wo*0zs8U_nXKJ-YT!y|(l9|sy;ambDM@h0XFh&)sPn8@TJShjSOHRE+0$1I*cL>5e zqFvs10yiz{S=6(lek~f{K{U95ig0xB{h{}JYDm){v37XAXTiP{E5APvybN|`DJHwL zb-9d$^C}f}vI^>CfI3Y;%x)!c1&V0~w7+d{#z9d+$rM$T+}P<^yk0{)`2 z+gNuV7L%){PAwLYA4r`bVhD8-E9tdvt2b&Ud&(mo6$<8d1~`p`r_M+;WO5(tE)4cfF!cr;4!2)cS&gZL>Wcv4ucJI2 z1N6f@vm56w6&=)}gH##nzZ2r8mQb%B1}#TU+PQFh(T}_<$TOmCKLnVyUV#&neZ-Se zedml2&tPGgEZ>y2z-sISjXfWO^&{y~w%}*3d5H6Xfe&M_4$PK$D8w7qgJs~w4+8IhbTv5fE;Csima(eN=yI1o0r^-w~@2ze2Pkjv>|}PJq4+ zxlm8_t|`#Fgd;{1fVrcIRu&$kmDYa>oJIqg1_kv%CtVLY{%Kl>~>IkmbA7wh+i(FB*5@q6NL|o#hM3+}s vSYA|7v8te`w6p?1S5aJ9goi$tAK5`A;n&(1_r;}?D-YhLax3YgOw7LlNUaFF diff --git a/krane-fb-stub.bin b/krane-fb-stub.bin index 0097f667958bb8fdae679e8a56a36e5f15c6ea7f..b5e5a401c2940222665842f460c7e91d2b2d935c 100755 GIT binary patch delta 1757 zcmah~ZERCj7=G_Px9!~run&v~lXbwhFf|>=xnzL06hc@J9zlo!lSVg&$@v z-pe)yu8HY|A2Vv$WeEhD_`@j48co(=Tp*wcT@VvV+HPeZ4E<3huCnd;9Kb{p6Pvtw zPTzCh=lwkA#$rnBl=4&=(OUY~FV^<(k8-M9ueO_3>vi@pk-bX!a*tm%MT>HMx`pg{ z#^O21aL>{6w_6k(aV?w?A{bgnkxV5e$Ze%mW~KaOeM)4d4iQCbJ3B_HjO=3?C8|kX zIDqrF3#U_T^I+=D!{6o^jpRLaG;sFFWM0d}Qg@iAp|gyxkB}9pBPVcdUCzuO>T>e5 zZ7_A1-~Ginv{jhaBMXU zraa2y9G2(*ILyaM{2E2h+!sMTc_MX344ynsPTu3P0wtNTintidyY}^_o>6#Wn(6Tw zW(E3dC)W29b@fwpeFqgstG(<-mQh?K)!x!dqag%0j^Kz~QIlw)2I~op+QZmSYqVW4 zS441@l=7|RWb4nqYzwC>qAa8AAd<2o#FIHjg$&~bMWgE=FE~P6{I6`2i{fI=gR`DT zXR(%NWm3vL5xfd68Q}5O8!K?QZUEVIC#ytB#{Q=s8L@T_nB4HHH}S& z9ugd?;!VTQ$pVKlhGSI}*^RwTKi4iE{NuxuXEiF9WWOSB8CYhsOpzz1c2PprfUg3P z;M879Ttd)@ev`dm(AQ^yB9}F&`3SlX$^< zDME~b{!%LUBLM$%WcQL9mG;+Qzp*piw6Y?0%&?6OcUfgTuhiP_XjVYOjU9NJH@Q8u zqirK^YF6BaWg@FI6&d4h3Vw{peng4yfMmX&7b<#d?Q5mDL<;x4Mbwysem4x$RBF^L ziC`Vb283wb>E^z3_eJB~ZM;x~@^`^z>v*j_@W}2b*gcQ4X{s;|{3U`i2x(X6LbYcK zqLCqDT*z44YAY~7b#@reuE6LDN^i>G7EyXQ?t{^H8uzs@u8z7G1f6M+%***kxsD@0_RK>!X~cMkh%2epTs=7wmf!9Ynz84Q#IXL6Vv1eAFLSOp9Ly}&SV3-E0q2O7Xu;JfnqvMPpF#8Alm908!0 zOkP1`s~_RMX~r7d$oinA#u*&U-6Ws>KKIT20_*{%ffn~^a5^`QbwBsbtZ{8c@aoXAe^J;OuCJ1w*ZAL}X`D*{ delta 1336 zcmb7EVQ5=b6h8O8mo#bPOxr;xtIbP03ub~A7fG0q+jNClW!UFKv><7_6?G59l>Lxe z_Fij;TjP&B`(uK#CdJ|w_Gjo1p9pP1M41RnDWW1KZKtbsQ!?4s+4cIpbi(kTfy;OA zIp;g)eD|K0>=esp*#kkMopjGHcyRl`rfh%6j_vTN_B4^bL>CSvC3AJ-OwrReSv+#| z^NNRNDqb4XK0LNq@t3ki(M6Z8$ll0DLAo?Umexi&ZDQAI<<;R_h4xMs&k{KVj_hJ- z{}T7mClMfRb}iEA7w^;NfkpCBhW$Re7$&;d>1P=g{shtbS3>AkWb*mqFaJrRO8+lO zQlWJIZ=t7DdC6T{LNu*Sy`(hx2W|`fM)lO8G(P+jb|Luhy!qL=F_tYdYo>BXCc7QN zuGi6q1mW%IrF|-|gv>yIJF<^E5^*O*%qaUwKkS?DW2LzUndHou#OlhjT<8V+9shja zHMu@=^)0d$oLdj@PiuHi^Y!O6zm?PQAldt|QsgyqjC8k)6xA60HKeD=XINGA8w+02 zS7cT|UbEmPaS01sLLUtBc&eF(m*LFOc7m>E9y4KEz&$2|WKTC!`Wg80-|xBA`PcDx zClso8lU;@E0f^}jawiM{gFCrHF7DzEvsl4;>ZGQwof~eg3MC^ik*+ExclIDq>ZjgR zE|K=ZIIdv7nMj|70+p*72})&X zWz1PO5}ZJSZZG_|MRa{P->5~=VQ_jDLiW&I-Z$WBh@GPbBfKGWx7jMs!{f8JL{x$> zG;3yic39dhsrDd>&4E z&vOC19yAm|;@2SPTMX)X*b*O5`qXuyOLzhXyMozRmZiw*UUE7y6Xiw|-vi!%`B8H4 zmc25DW#w^l*y}uAUZl9^7>{564)_M}N8l*%XP^aK0ZssarT7VO=_HSr)+t^RZ)+(c zV 1920) + break; + for (u32 b = 0; b < 32; b++) { + u32 c = ((d[i] >> (31 - b)) & 1) ? 0x00FFFFFFu + : 0x00000000u; + for (u32 yy = 0; yy < 32; yy++) { + volatile u32 *row = fb + + (u64)(y0 + yy) * DIAG_FB_WIDTH + b * 32; + for (u32 xx = 0; xx < 32; xx++) + row[xx] = c; + } + } + } +} + +static void fail_dump(u32 marker, const u32 *words, int n) +{ + u32 diag[16]; + for (int i = 0; i < 16; i++) + diag[i] = 0; + + diag[0] = marker; + for (int i = 0; i < n && i < 15; i++) + diag[1 + i] = words[i]; + + blink_backlight(5); /* audible-free "I ran" signal */ + render_diag(diag, 16); + halt(); +} + /* ---- main checkpoint sequence ------------------------------------------- */ static void checkpoint(const struct fbinfo *f, int r, int g, int b) @@ -322,13 +372,6 @@ static void checkpoint(const struct fbinfo *f, int r, int g, int b) delay_ms(2000); } -/* Parse failure: black screen + 5 slow backlight blinks, then spin. */ -static void parse_fail(void) -{ - blink_backlight(5); - halt(); -} - void cmain(u64 dtb) { struct fbinfo fb; @@ -337,11 +380,30 @@ void cmain(u64 dtb) stage0(); - if (find_coreboot_reg((const void *)dtb, &lbio_addr, &lbio_size)) - parse_fail(); /* 5 blinks: DTB parse failed */ + if (find_coreboot_reg((const void *)dtb, &lbio_addr, &lbio_size)) { + /* Dump the DTB header words + the x0 pointer itself. */ + const volatile u32 *dt = (const volatile u32 *)dtb; + u32 w[6] = { + (u32)dtb, (u32)(dtb >> 32), + dt[0], dt[1], dt[2], dt[3], + }; + fail_dump(0xC0DE0001u, w, 6); + } - if (find_framebuffer(lbio_addr, &fb)) - parse_fail(); /* 5 blinks: LBIO/fb record bad */ + int rc = find_framebuffer(lbio_addr, &fb); + if (rc) { + /* Dump the LBIO location + raw table header + raw words at + * several offsets, exactly as found in memory. */ + const volatile u32 *t = (const volatile u32 *)lbio_addr; + u32 w[12] = { + (u32)lbio_addr, (u32)(lbio_addr >> 32), lbio_size, + t[0], t[1], t[5], /* magic, header_bytes, entries */ + t[6], t[7], /* rec0 tag, size (if hb=24) */ + t[8], t[9], /* raw words at +32, +36 */ + t[16], t[17], /* raw words at +64, +68 */ + }; + fail_dump(0xC0DE0002u | (u32)rc, w, 12); + } /* Checkpoint 1: red — parsed; LBIO framebuffer record is sane. */ checkpoint(&fb, 1, 0, 0); /* red */