The bootrom linker script defines __bss_end__ before COMMON symbols are
placed. Startup clears only up to that boundary. On PM5 with ARM GCC 8.5,
this leaves the entire 92-byte USB CDC structure outside the zeroed area,
even though bootrom sources themselves are built with -fno-common.
Place COMMON inside .bss before setting __bss_end__, and assert that the
boundary covers the whole section. The shared script applies to PM5 and
RDV4. On the tested PM5 build, stack addresses, the shared communication
area and the entry point remain unchanged.
Built both targets with ARM GCC 8.5 and ran bootrom/check. Checked ELF
boundaries and the 16 KiB boot partition; removing COMMON placement
triggers the new assertion. No compiler warnings; the existing PM5 RWX
LOAD-segment linker warning remains. CMake and BWM builds were not tested.
Flashed the bootrom alone on PM5 and verified readback against the image.
All internal flash bytes from the OS start onward matched the pre-flash
backup. Cold startup and five software reset cycles passed. Five complete
bootloader/read/reset cycles also passed after fixing the client's dump
cleanup separately. FPGA was not written. This corrects initialization;
it does not establish a fix for the USB-controller failures in #3642.
Bootloader memory-dump cleanup sends CMD_PING to wake the communication
thread after clearing its run flag. The thread can be waiting for another
transmit after the dump ACK, so it sends this command before exiting.
The non-BWM bootrom does not handle CMD_PING: its default dispatch enters
Fatal(), leaving the device unresponsive even though the dump succeeded.
Use CMD_DEVICE_INFO for the wakeup instead. It is already supported by the
bootloader and used to identify it before the dump. Keep the wakeup so
closing the client does not leave the communication thread waiting.
Reproduced on PM5: the dump completed, but the following reset and device
probe failed. With only the rebuilt client changed, the same test script
passed five OS-to-bootloader, memory-dump and reset-to-OS cycles, with a
successful ping after each. No firmware was flashed for this comparison.
Built the client with AppleClang through Make, CMake and experimental_lib;
client/check passed. GCC 16 compiled the changed translation unit with
-Wall -Werror. Existing macOS linker warnings remain. The full GCC host
build was not repeated because of the previously observed Apple SDK
alignment error. Linux and Windows were not tested; this change replaces
an existing protocol command without changing platform-specific code.
Problem
The native hf mfu countertear used a device-side
CMD_HF_MFU_COUNTER_TEAROFF path with a static increment payload,
decided once per run. The pyscript mfuev1_counter_reset.py implements
the same attack with auto-calibration, a 3-phase attack loop,
per-attempt BD delay tuning (hunting) and stuck-value handling,
which the native command lacked.
Change
- rewrite the client command around the generic tear-off hook
(hw tearoff) and raw INCREASE_CNT frames, mirroring the pyscript
step by step: preflight checks, CHECK_TEARING_EVENT support gate,
targeted repair/normalize, BD sweep calibration (working delay
accepted only on 0xBD), and the DECREMENT -> PREPARE (0x00FFFF)
-> RESET phases with the same increment payloads (000100 for
decrement steps, 010000 for reset/repair)
- same delay tuning on counter movement: +1 when unchanged, -1 when
a jump exceeds 10, delay locked after a successful decrement
- remove CMD_HF_MFU_COUNTER_TEAROFF usage from the client; device
side stays untouched
- add Lua port client/luascripts/mfuev1_counter_reset.lua with the
same behaviour, using core.console capture and Enter-to-stop
- regenerate doc/commands.md and doc/commands.json
Behaviour change
Same CLI shape as the pyscript (-c/-f/--DelayBD/--Delay00, legacy
-i/-l/-s/-x options removed). Console output now matches the pyscript.
Testing
gcc warningless for client, armsrc and bootrom (RDV4). make check
green. doc regenerated with GD enabled. Verified 1:1 against the
pyscript and the new Lua port on hardware (EV1 card). Not tested
here: clang, Windows/ProxSpace and macOS. No build files are touched,
so the usual client-side review applies.
Co-Authored-By: opencode agent (GLM-5.3-Flash-Free) <noreply@opencode.ai>
Validate counter choices 0-2, treat only 0x00/0xBD as valid
CHECK_TEARING_EVENT answers, and detect NACK replies from the raw
payload, so retry logic does not mistake a NACK for a real answer.
Building the client with -march=x86-64-v3 (the CentOS/RHEL 10
baseline) fails with gcc 14:
src/emv/emvcore.c:211:24: error: writing 32 bytes into a region of
size 22 [-Werror=stringop-overflow=]
gcc vectorizes the dash fill loop in aidlist_rule() into 32-byte
stores and loses the pos + 2 < dstlen bound. The bound was correct.
Compute the dash count with the same limit and fill it with memset,
so there is no vectorized loop store to mis-size. Output is unchanged.
Reported in #3671.
Co-Authored-By: Grok Bot <noreply@users.noreply.github.com>
SPI1 is full-duplex with no RX FIFO. Every byte cep_spi_write_sync()
clocks out on MISO also shifts a byte in on MOSI that nothing reads,
and AT32F435/437 RM ch 13.2.9 says the first such byte freezes in
SPI_DT until read - not "newest overwrites oldest" as assumed before.
A frozen byte then gets misread by cep_spi_data_available() as part of
the next frame's length header, forcing a resync. Clear ROERR once
after the write (before the read path can touch it) and once at the
top of the read path (for freezes from other main-loop gaps).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Following discussions and debugging with the hardware engineer, the PWM clock frequency was reduced from 400 MHz to 200 MHz. Subsequent testing confirmed that voltage regulation remained largely unaffected.
The cache is keyed on a hash of the graph buffer contents: the buffer has
many writers and no change counter.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace the artificial 68-pair limit with a 2900 ms inter-attempt
budget.
A completed-pair count does not limit failed RF/authentication retries
and unnecessarily restricts fast PM5 collection.
Keep natural buffer capacity, whole-pair packing, client cancellation,
watchdog handling and the existing 3000 ms client response waits.
A blocking attempt can overshoot; persistent errors may yield an empty
nonce reply.
Add actual-handler regression coverage for PM5, RDV4 and GENERIC.
Co-Authored-By: OpenAI coding assistant <noreply@openai.com>
Signed-off-by: nip <182409448+nip-was-here@users.noreply.github.com>
Validate byte length, unfinished bits, collisions and parity-buffer
length before accepting an encrypted nested nonce. Capture decoder
metadata before CHK_TIMEOUT changes it and retry incomplete responses.
Remove the PM5-only 500 us nested-authentication delay and its override.
Preserve other RF timing, the pair cap, cancellation and watchdog calls.
Add native regression coverage without target-key filtering.
Co-Authored-By: OpenAI coding assistant <noreply@openai.com>
Signed-off-by: nip <182409448+nip-was-here@users.noreply.github.com>
Add an opt-in simulator probe that checks a reader's AES authentication continuation against a supplied candidate and stops before the final card response. Expose the result through the firmware protocol and etest bench command, and document the evidence and handshake scope.
Co-Authored-By: OpenAI Codex <noreply@openai.com>