diff --git a/RESEARCH.md b/RESEARCH.md index b7766fd..17b544d 100644 --- a/RESEARCH.md +++ b/RESEARCH.md @@ -194,20 +194,63 @@ disassembly before reboot), flashed to `mmcblk0p1`, `cmp` + ## Flash state -- `mmcblk0p1` reflashed with the revival payload: - sha256 `9e7cf29d3cddb83cda957a469ff5fb0dea70a2d67c9a6cc0a1f1497b19bc8756`, +- `mmcblk0p1` reflashed with the Round-3 diagnostic payload: + sha256 `9d7859dc04dd9c445143f6b45600bb972cf5fc1497c06a4f9db549e3d2971e73`, verified on-device (`cmp` first 159,744 bytes + `vbutil_kernel --verify` - → body verification succeeded). (Round-1 payload was `edb65b29…`.) + → body verification succeeded). Earlier: Round-1 `edb65b29…`, Round-2 + `9e7cf29d…` (both functionally identical wrong-offset code; `41270e53…` + was a stale-tree rebuild caught by disassembly). - USB stick `sda1` untouched throughout (sha256 watched: `c4ee2044…`). - eMMC backup: `~/mmcblk0p1-pmos-backup.img` (sha256 `20951a54…`). **Copy it onto the USB stick before rebooting** so recovery never depends on eMMC. + +## Round 3 — still black with corrected offset; diagnostic stub + +Reboot with payload `9e7cf29d…` (correct `OVL_EN=0x000C`): still pitch +black. Fact check: all four teardown steps of device-era `display_cleanup` +are now provably undone — `clear_screen(black)` (repainted), the backlight +GPIOs (matches `kukui_backlight_update`), `OVL_EN`/`OVL0_2L_EN` (correct +offsets), and `disable_graphics_buffer()` (a libpayload double-buffer +helper, no hardware effect). Device-era `init_screen()` sequencing +(`ui/display.c`) proves the dev menu was drawn into the LBIO +`physical_address` and scanned out via `OVL_L0_ADDR` = same address, so the +stub's fills go to the right buffer. Revival logic is correct on paper — +yet black. + +**The unexcluded branch: the stub may never execute.** "Menu vanished" only +proves depthcharge reached handoff — cleanup runs unconditionally. And the +internal-boot path was never baseline-proven: pmOS always ran from USB; no +custom image has ever been observed booting from p1 on this device. Every +black screen so far is equally consistent with "payload never ran". + +### Diagnostic design (payload `9d7859dc…`) + +Payload now paints/blinks BEFORE trusting any parsing: + +1. First instructions: `OVL_EN=1`, `OVL0_2L_EN=1`, backlight GPIOs on. +2. Parse (<1 ms). Failure → 5 slow backlight blinks, spin. +3. Success → red → yellow → green → blue, blue held. + +Decision tree: colors = pipeline validated; 5 blinks on black = parse +failed at runtime; nothing at all = payload never handed off (boot path). + +### Abandoned: OVL_L0_ADDR stage-0 read + +An earlier design read `OVL_L0_ADDR` (0x14008F40) pre-parse to paint the +menu buffer without knowing `pa`. Rejected: on qemu `-M virt`, READS of +unassigned MMIO data-abort (writes are silently dropped) — it killed the +test instantly; the same risk exists on real hardware if a display clock +gate is off, and a fault there is indistinguishable from "never ran". The +stub now contains no MMIO reads at all. + ## Diagnostic decision tree (after this fix) | observation | meaning | |---|---| -| menu exits → black immediately, no color | stub ran but died in DTB/LBIO parse (or OVL revive didn't take) | +| black, no colors, no blink | payload never handed off — boot-path problem (vboot/mkdepthcharge), investigate p1 boot | +| black + 5 slow backlight blinks | stub ran, parse failed at runtime | | colors appear but sequence stops early | fill/mask problem — stuck color identifies stage | | red → yellow → green → blue, blue held | pipeline fully validated | diff --git a/krane-fb-stub-payload.bin b/krane-fb-stub-payload.bin index 3e52973..ce0eafd 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 54906d2..287480a 100755 Binary files a/krane-fb-stub.bin and b/krane-fb-stub.bin differ diff --git a/main.c b/main.c index 3dfded2..b14937e 100644 --- a/main.c +++ b/main.c @@ -248,6 +248,7 @@ static void fill_screen(const struct fbinfo *f, u64 val) #define DISP_OVL0_BASE 0x14008000u #define DISP_REG_OVL_EN 0x000Cu /* mtk_ddp.c, both mt8173/mt8183 */ +#define DISP_REG_OVL_L0_ADDR 0x0F40u /* scanout address, survives stop */ #define DISP_REG_OVL0_2L_EN 0x100Cu /* 2021 mtk_ddp.c */ #define GPIO_BASE 0x10005000u @@ -263,14 +264,40 @@ static void wr32(u64 addr, u32 val) *(volatile u32 *)addr = val; } -/* Undo depthcharge's display_cleanup() so our fills are visible. */ -static void display_revive(void) +/* ---- main checkpoint sequence ------------------------------------------- */ +/* + * The krane panel (BOE TV101WUM_NL6) is 1200x1920 xRGB8888 — the menu + * buffer depthcharge scanned out (OVL_L0_ADDR, programmed from the LBIO + * record's physical_address) has exactly that geometry. So painting the + * parsed LBIO pa IS repainting the still-registered scanout buffer. + * Note: we deliberately never READ OVL registers — MMIO reads to a gated + * display module can data-abort (qemu -M virt aborts on such reads too, + * which killed an earlier stage-0 design); writes are always safe. + */ + +static void blink_backlight(int times) { - /* Same buffer depthcharge scanned out for the menu. */ + for (int i = 0; i < times; i++) { + wr32(GPIO_DOUT_SET(PAD_DISP_PWM), 0); + wr32(GPIO_DOUT_SET(PAD_EN_LCD_BL), 0); + delay_ms(300); + wr32(GPIO_DOUT_SET(PAD_DISP_PWM), GPIO_DOUT_BIT(PAD_DISP_PWM)); + wr32(GPIO_DOUT_SET(PAD_EN_LCD_BL), GPIO_DOUT_BIT(PAD_EN_LCD_BL)); + delay_ms(300); + } +} + +static void stage0(void) +{ + /* + * Stage 0 — first instructions after entry, BEFORE any parsing. + * Backlight on + OVL engine re-enabled (undoing depthcharge's + * cleanup). No reads, no parse: if even this never becomes visible, + * the payload was never handed off (boot-path problem), not a + * display-revival problem. + */ wr32(DISP_OVL0_BASE + DISP_REG_OVL_EN, 1); wr32(DISP_OVL0_BASE + DISP_REG_OVL0_2L_EN, 1); - - /* Backlight on (both pins), matching kukui_backlight_update(true). */ wr32(GPIO_DOUT_SET(PAD_DISP_PWM), GPIO_DOUT_BIT(PAD_DISP_PWM)); wr32(GPIO_DOUT_SET(PAD_EN_LCD_BL), GPIO_DOUT_BIT(PAD_EN_LCD_BL)); } @@ -283,33 +310,34 @@ 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; u64 lbio_addr; u32 lbio_size; - /* - * Parse everything first (instantaneous). On failure halt unpainted: - * depthcharge blacked the screen and disabled the OVL engine, so the - * failure signature is a black screen right after the menu. - */ + stage0(); + if (find_coreboot_reg((const void *)dtb, &lbio_addr, &lbio_size)) - halt(); /* black screen: DTB parse failed */ + parse_fail(); /* 5 blinks: DTB parse failed */ if (find_framebuffer(lbio_addr, &fb)) - halt(); /* black screen: LBIO/fb record bad */ + parse_fail(); /* 5 blinks: LBIO/fb record bad */ - /* Re-enable scanout + backlight, then paint. */ - display_revive(); - - /* Checkpoint 1: red — we entered, parsed, revived the display. */ + /* Checkpoint 1: red — parsed; LBIO framebuffer record is sane. */ checkpoint(&fb, 1, 0, 0); /* red */ - /* Checkpoint 2: yellow — DTB stage. */ + /* Checkpoint 2: yellow. */ checkpoint(&fb, 1, 1, 0); /* yellow */ - /* Checkpoint 3: green — LBIO + framebuffer record found. */ + /* Checkpoint 3: green. */ checkpoint(&fb, 0, 1, 0); /* green */ - /* Checkpoint 4: blue — all earlier fills visibly succeeded. */ + /* Checkpoint 4: blue — hold. */ checkpoint(&fb, 0, 0, 1); /* blue */ halt(); /* hold blue forever */