stub: accept LBIO physical_address == 0 — it is the real record here
Round 5: the Round-4 diagnostic blinks decoded as parse_fail. Root cause confirmed in coreboot 4.14 source (kukui mainboard.c + edid_fill_fb.c): the LBIO framebuffer record genuinely has physical_address = 0 — the menu renders through DRAM address 0, which the never-stopped OVL scans out (display_init_required() is false, so depthcharge registers no display ops and its handoff cleanup's backlight/stop calls are no-ops). Round-2's 'menu proves pa != 0' reasoning was wrong; the original open-item note was right. The stub's !fb->pa rejection caused every parse failure. find_framebuffer now accepts pa == 0 and the stub paints at address 0, the same region depthcharge's own cleanup black-fills. host_test gained a pa==0 regression test; qemu_test unchanged. Payload b25d9132... flashed and verified (cmp + vbutil).
This commit is contained in:
+37
@@ -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`.
|
||||
|
||||
|
||||
+30
@@ -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;
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user