test(web): seed SD before autoboot; document upstream store-TCI root cause
The file browser no longer auto-seeds, so the headless test seeds Test/example.txt into OPFS before autoboot. Docs corrected: store-containing-TB TCI is upstream qemu-wasm design (compiled store path is not rewind-safe), not a port bug.
This commit is contained in:
@@ -8,11 +8,13 @@ Opening `/Test/example.txt` through QEMU `vvfat` could corrupt coroutine/guest s
|
||||
|
||||
`ssi-sd` consumed a write-data token while leaving response mode, then parsed payload bytes as commands. The adapter now enters token mode immediately after the final R1 byte. SPI CMD13 also uses the upstream-correct `sd_r1` internal response so status polling no longer loops on `Unexpected response to cmd 13`.
|
||||
|
||||
## Worked around: WASM reader panic in uzlib font decompression
|
||||
## Upstream limitation: compiled wasm32 store path (perf ceiling)
|
||||
|
||||
Opening a book panicked **only in WASM** (`Invalid read ... reason: rejected` → Load access fault) inside `uzlib_uncompress` during the reader's font `prewarmCache`. Native QEMU from the same submodule decompresses the identical static flash font and renders text, so it is a wasm32 TCG backend miscompile, not firmware/SD.
|
||||
Opening a book panics **only in WASM** (`Invalid read ... reason: rejected` → Load access fault) inside `uzlib_uncompress` during the reader's font `prewarmCache` **if** compiled guest stores are enabled. Native QEMU from the same submodule renders fine.
|
||||
|
||||
Worked around by forcing store-containing TBs to TCI (`wasm_tci_only_tb = true` in `tcg_out_qemu_st`). Reader now opens and paints in the browser. This is a workaround with a perf ceiling (store-containing TBs run interpreted); the precise miscompiled op is not yet localized. Full investigation and next steps: `docs/wasm-inflate-panic.md`.
|
||||
Root cause (confirmed by full diff against pristine upstream): `wasm_tci_only_tb = true` in `tcg_out_qemu_st` is **upstream qemu-wasm's own design**. Upstream forces every store-containing TB to the TCI interpreter because its compiled restartable-block store path is not rewind-safe (a yielded softmmu helper replays the block; safe for loads, corrupting for stores). This is the dominant cost of book open (font inflate is store-heavy, so the hot loop never JIT-promotes).
|
||||
|
||||
The real fix is to make compiled stores rewind-safe and drop the blanket TCI — a substantial TCG-backend task, ~15 min per browser iteration, no native repro. Full analysis: `docs/wasm-inflate-panic.md`.
|
||||
|
||||
## Resolved: reader grayscale rendered inverted and muddled
|
||||
|
||||
|
||||
@@ -14,6 +14,29 @@ Guru Meditation Error: Core 0 panic'ed (Load access fault). Exception was unhand
|
||||
MEPC : 0x4201e210 RA : 0x4201e18c SP : 0x3fcb3810
|
||||
```
|
||||
|
||||
## Root cause (established)
|
||||
|
||||
`wasm_tci_only_tb = true` in `tcg_out_qemu_st` is **upstream qemu-wasm's own
|
||||
design**, not a workaround this project invented. A full diff of our
|
||||
`tcg/wasm32/tcg-target.c.inc` against pristine upstream qemu-wasm shows the two
|
||||
files are identical except for that one line. Upstream unconditionally forces
|
||||
every store-containing TB to the TCI interpreter, so upstream's *compiled*
|
||||
(JIT) store path is emitted but never executed — it is effectively unfinished,
|
||||
untested dead code, and it corrupts guest state the moment it runs.
|
||||
|
||||
Mechanism: the wasm32 backend compiles a TB as a chain of wasm blocks guarded
|
||||
by `if (BLOCK_PTR <= block_idx)`. When a softmmu slow-path helper yields
|
||||
(asyncify unwind for I/O / interrupt), the wasm function returns and re-enters,
|
||||
skipping already-executed blocks via `BLOCK_PTR`. This restart is safe to
|
||||
replay for loads but not for a compiled store, so upstream punts all store TBs
|
||||
to TCI (which has precise instruction-level checkpointing).
|
||||
|
||||
The real fix is therefore not a port bug hunt but completing upstream's
|
||||
compiled store path to be rewind-safe (e.g. defer the memory commit past the
|
||||
TB's yield points / buffer stores until block commit), then dropping the
|
||||
blanket TCI. Large TCG-backend task; ~15 min per browser iteration; no native
|
||||
repro.
|
||||
|
||||
## Established facts
|
||||
|
||||
- **Fault site (via same-version local ELF addr2line, not byte-identical):**
|
||||
|
||||
@@ -115,6 +115,22 @@ try:
|
||||
'?firmware=/_scratch/crosspoint-reader-1.4.1-release-firmware.bin'
|
||||
f'&variant=x3{suffix}',
|
||||
)
|
||||
# Seed the SD card in OPFS before autoboot; the app no longer auto-seeds.
|
||||
base = url.split('?')[0]
|
||||
driver.get(base)
|
||||
seed = driver.execute_async_script('''
|
||||
const done = arguments[arguments.length - 1];
|
||||
import('./sdstore.js').then(async m => {
|
||||
const lorem = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.';
|
||||
const nl = String.fromCharCode(10, 10);
|
||||
const text = Array(10).fill(lorem).join(nl);
|
||||
await m.clearSdFiles().catch(() => {});
|
||||
await m.writeSdFile('Test/example.txt', text);
|
||||
done('ok');
|
||||
}).catch(e => done('err: ' + e));
|
||||
''')
|
||||
if seed != 'ok':
|
||||
raise RuntimeError(f'failed to seed SD card: {seed}')
|
||||
driver.get(url)
|
||||
|
||||
confirm = driver.find_element(By.CSS_SELECTOR, '[data-button="confirm"]')
|
||||
|
||||
Vendored
+1
-1
Submodule third_party/qemu updated: 962fc6e71d...7cab93ede7
Reference in New Issue
Block a user