summaryrefslogtreecommitdiff
path: root/cpu-docs
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-08-25 14:56:24 -0300
committerGabriel Schneider <[email protected]>2026-08-25 14:56:24 -0300
commitd69785542ced9bd24d210e38788e8eab42d678ad (patch)
treea56fcdfbb20fdee03bf5d7b366620485f50870a2 /cpu-docs
parent174991b8f3f8e9c792eede7a52ad7beb10a08b05 (diff)
downloadesp32p4-d69785542ced9bd24d210e38788e8eab42d678ad.tar.gz
esp32p4-d69785542ced9bd24d210e38788e8eab42d678ad.zip
Flush the caches at startup: the bootloader hands over stale lines
The image reads its own .rodata and gets its own .text back, and after ruling out everything cheaper the answer is the cache. What was eliminated first, each by measurement rather than argument: * The MMU table is CORRECT. Read from the running application through SPI_MEM_C_MMU_ITEM_INDEX_REG/CONTENT_REG (hal/esp32p4/mmu_ll.h:311-330), entries 0..9 hold 0x1001..0x100a - the valid bit plus physical page N+1 - which is exactly what the image builder's single flash-to-vaddr anchor requires, and entries 10..11 are unmapped as they should be. * The page size is not in question: hardwired to 64 KiB on this chip (mmu_ll.h:126-130 returns MMU_PAGE_64KB and the setter asserts it), which is what tools/image.zig already assumed. * The flash is correct. The flasher verifies an MD5 of what the ROM stored, and app.bin matches the ELF byte for byte at the addresses that misread. * Not a write failure and not nondeterminism: identical across three resets and two reflashes with the same MD5. * Not 64-byte cache-line granularity either: the wrong bytes come in a contiguous run of at least 192. The measurement that settles it: a load at 0x40035a1c returned 93 85 85 0f, and reading 512 KiB to force capacity eviction made the SAME load return 3c ee 08 40, which is what the image holds there. So the second-stage bootloader hands over with cache lines that do not match the mapping it finally installed. It is perfectly deterministic - the bootloader does the same thing every boot, so it leaves the same lines - which is precisely why it looked like anything other than a cache for so long. The ROM's own Cache_Invalidate_All (0x4fc00404, the same address in both esp32p4.rom.ld and the eco5 table) would be the right instrument and is NOT used: called from here it faults inside ROM code with its argument stranded in a2, so it wants a precondition this image does not know. A capacity flush needs no such knowledge, costs one pass over 512 KiB of already-mapped flash once at boot, and is four times the 128 KiB the L2 measured at. Effect: the firmware now gets through the editor's allocator round-trip and pardes.allocators.init, which is two steps further than before. Also here, and correct independently of any of the above: uart.write and writeByte no longer spin forever on a stalled transmitter. hal/uart.zig:182-186 already made this point about update() - "on a board with no debugger an infinite spin is indistinguishable from a crash" - and this port proved it by spending an afternoon reading a stalled console as a hang in whatever code came next. The wait is bounded and abandoned bytes are counted. Still open: the console stops immediately after pardes.allocators.init. Bounded writes did not change it, so it is not the transmit spin; there is no Guru Meditation, so it is not a trap the ROM can report. The p4 allocator tier's zero-capacity StackFallbackAllocators are the one unusual thing in that call and their reasoning against lib/std/heap.zig is written down in src/allocators.zig, but it has not been tested with a nonzero floor. The bisect markers are left in place for that.
Diffstat (limited to 'cpu-docs')
0 files changed, 0 insertions, 0 deletions