diff --git a/RESEARCH.md b/RESEARCH.md index 8462902..5d2ccee 100644 --- a/RESEARCH.md +++ b/RESEARCH.md @@ -284,6 +284,43 @@ Payload `55ccc1bd…` flashed (cmp + vbutil OK). host/qemu tests pass. | colors appear but sequence stops early | fill/mask problem — stuck color identifies stage | | red → yellow → green → blue, blue held | pipeline fully validated | +## Round 5 — blinks decoded: LBIO physical_address really IS 0 + +The Round-4 payload's diagnostic worked: 3–5 backlight blinks then steady +backlit black = `parse_fail()`. The stub runs, stage-0 works, the GPIO fix +works — the parse rejected the LBIO framebuffer record. Root cause found +in the actual coreboot **4.14** source (fetched from the 4.14 tag): + +- `src/mainboard/google/kukui/mainboard.c` (4.14) is identical to + mainline: `fb_new_framebuffer_info_from_edid(edid, 0)` — and 4.14's + `edid_fill_fb.c` passes `fb_addr` through verbatim, no carveout, no + allocation. **The LBIO record on this device genuinely has + physical_address = 0.** + +How the menu still renders: libpayload cbgfx draws into +`phys_to_virt(pa)` = DRAM address 0, and coreboot's display pipeline scans +out address 0. With `pa = 0`, depthcharge's `display_init_required()` is +false, so board.c never registers display ops — meaning at handoff +`display_cleanup` runs but `backlight_update` and `stop` are no-ops: +**the OVL was never stopped and the backlight never disabled by +depthcharge.** The "menu vanishing" was just the 9.2 MB black fill at +address 0 (safe for the payload: depthcharge itself does it after the +kernel slot is chosen, and the stub demonstrably survived every round). + +**Round-2's "open item resolved" reasoning was wrong** — menu rendering +does NOT prove pa != 0, because address 0 works as a framebuffer region. +The original Phase-1 note ("mainline coreboot passes fb_addr=0 for kukui") +was correct all along. All five black screens so far trace to the stub's +`!fb->pa` rejection of a legitimate record (plus the two Round-1 register +offset misreads, which additionally kept the backlight dark). + +Fix: `find_framebuffer` accepts `pa == 0` and the stub paints at address +0 — the buffer the still-running OVL scans. OVL revival and backlight +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). + Recovery: power-cycle, boot USB (unchanged), `dd if=mmcblk0p1-pmos-backup.img of=/dev/mmcblk0p1 bs=4M conv=fsync`. diff --git a/host_test.c b/host_test.c index 736474a..fddb1a6 100644 --- a/host_test.c +++ b/host_test.c @@ -103,6 +103,36 @@ int main(void) (unsigned long)fbmem[1200 * 7680 + 32], 0xAA); } + /* --- test 3: device-realistic pa==0 record must be accepted ---------- */ + /* coreboot 4.14 kukui publishes physical_address = 0; depthcharge's + * menu renders through DRAM address 0. Regression guard for the + * Round-5 bug (blinking parse_fail on the real device). */ + { + memset(table, 0, sizeof table); + memcpy(table, "LBIO", 4); + put32(table + 4, 24); + put32(table + 20, 1); + u8 *r = table + 24; + put32(r, 0x12); + put32(r + 4, 48); + put32(r + 8, 0); /* physical_address = 0 */ + put32(r + 12, 0); + put32(r + 16, 1200); /* x */ + put32(r + 20, 1920); /* y */ + put32(r + 24, 4800); /* bytes_per_line */ + r[28] = 32; /* bpp */ + r[29] = 16; r[30] = 8; + r[31] = 8; r[32] = 8; + r[33] = 0; r[34] = 8; + + struct fbinfo fb0; + int rc0 = find_framebuffer((u64)(unsigned long)table, &fb0); + check("pa==0 record accepted", (unsigned long long)(rc0 == 0), 1); + check("pa==0 fb pa stays 0", fb0.pa, 0); + check("pa==0 xres", fb0.xres, 1200); + check("pa==0 mkcolor red", mkcolor(&fb0, 1, 0, 0), 0x00ff0000ull); + } + printf(fails ? "\nFAILED: %d\n" : "\nALL PASS\n", fails); return fails != 0; } diff --git a/krane-fb-stub-payload.bin b/krane-fb-stub-payload.bin index c117429..59fd62f 100644 Binary files a/krane-fb-stub-payload.bin and b/krane-fb-stub-payload.bin differ diff --git a/krane-fb-stub.bin b/krane-fb-stub.bin index 2f0e88a..0097f66 100755 Binary files a/krane-fb-stub.bin and b/krane-fb-stub.bin differ diff --git a/main.c b/main.c index 9fa575f..2afb423 100644 --- a/main.c +++ b/main.c @@ -150,6 +150,13 @@ static int find_coreboot_reg(const void *dt, u64 *addr, u32 *size) * bits_per_pixel @28, red_pos/size @29/30, green @31/32, * blue @33/34, reserved @35/36, orientation @37, flags @38, pad @39 * sizeof(struct lb_framebuffer) == 40 (host-verified with real header). + * + * **physical_address == 0 is LEGITIMATE on this device**: coreboot 4.14 + * kukui calls fb_new_framebuffer_info_from_edid(edid, 0) with no carveout, + * so the LBIO record really says pa=0 and depthcharge's UI draws its menu + * into DRAM address 0, which the (never-stopped) OVL scans out. Do NOT + * reject it; paint at address 0 — the same 9.2 MB region depthcharge's own + * display_cleanup black-fills at handoff. */ static int find_framebuffer(u64 table, struct fbinfo *fb) { @@ -173,6 +180,7 @@ static int find_framebuffer(u64 table, struct fbinfo *fb) if (tag == LB_TAG_FRAMEBUFFER) { if (rsize < 40) return -1; + /* pa == 0 is legitimate here (see block comment). */ fb->pa = (u64)rd32le(rec + 8) | (u64)rd32le(rec + 12) << 32; fb->xres = rd32le(rec + 16); @@ -182,7 +190,7 @@ static int find_framebuffer(u64 table, struct fbinfo *fb) fb->rpos = rec[29]; fb->rsize = rec[30]; fb->gpos = rec[31]; fb->gsize = rec[32]; fb->bpos = rec[33]; fb->bsize = rec[34]; - if (!fb->pa || !fb->xres || !fb->yres || !fb->bpl) + if (!fb->xres || !fb->yres || !fb->bpl) return -1; if (fb->bpp % 8 || fb->bpp < 8 || fb->bpp > 32) return -1;