'hf legic eload' writes emulator memory as a burst of back-to-back
packets. CMD_HF_LEGIC_ESET called FpgaDownloadAndGo(FPGA_BITSTREAM_HF)
on every one of them, and when that actually had a bitstream to download
the device stopped servicing USB for long enough that the packets already
in flight behind it were dropped.
Reproducible, and it only shows after a command that left a different
bitstream loaded, which is why it has gone unnoticed:
hf iclass eload ... # loads FPGA_BITSTREAM_HF_15
hf legic eload -f x.bin # first packet downloads FPGA_BITSTREAM_HF
hf legic esave --1024 # 404 bytes of 1024 come back as zeros
The boundary is always 619, which is max_cmd_data_size minus
sizeof(legic_packet_t) -- exactly one packet. Back to back a second time
it works, because the bitstream is then already loaded. The 'fast push
mode' in legic_seteml() is not involved: block_after_ACK only applies to
OLD frames and these are NG.
So the handler does no FPGA work at all now. The comment it used to carry
-- 'if it is called later, it might destroy the Emulator Memory' -- was
aiming at a real problem but solving it at the wrong end. init_tag() in
legicrfsim.c is where the bitstream is genuinely needed, and it was using
the plain variant twelve lines above 'legic_mem = BigBuf_get_EM_addr()',
so 'hf legic sim' was wiping the image it was about to serve. That one
becomes _keep_EM.
Five sibling handlers carry the same copy-pasted comment and the same
wipe-before-use pattern and are switched to _keep_EM as well:
CMD_LF_EM4X50_SIM (em4x50_sim reads its tag out of emulator memory),
CMD_LF_EM4X50_ESET, CMD_HF_ISO15693_EML_SETMEM, EML_GETMEM and
CMD_HF_MIFARE_EML_MEMCLR. Only the LEGIC path has a reproducer; the rest
is the same fix applied where the same mistake is visible.
Verified on an RDV4: the reproducer above now loses 0 bytes over three
runs, 'hf legic sim' reports the MCD/MSN of the uploaded image, and
eload/esave still round-trips byte-identical for MIFARE Classic 4K,
iso15693 and iCLASS.
Co-Authored-By: Claude Opus 5 (1M context)