Random corruption on SpacemiT K1 (and K3) with RVV
Palmer Dabbelt
palmer at dabbelt.com
Thu Sep 17 12:18:59 PDT 2026
On Tue, 15 Sep 2026 14:14:10 PDT (-0700), aurelien at aurel32.net wrote:
> Hi,
>
> Some more update, even if the progress is quite low.
Well, thanks for digging into this.
>
> On 2026-09-09 18:45, Aurelien Jarno wrote:
>> [Added Andy and Karl in Cc: as they have been involved in the vectored
>> user copy code and fighting similar issues]
>>
>> Hi,
>>
>> Some more progress on that topic.
>>
>> On 2026-09-08 06:42, Aurelien Jarno wrote:
>> > Dear all,
>> >
>> > I have done some small progress on that issue. Help is still wanted and
>> > would be appreciated.
>> >
>> > On 2026-08-30 22:52, Aurelien Jarno wrote:
>> > > Dear all,
>> > >
>> > > For the last weeks, I have been tracking a random memory corruption and
>> > > relatively rare on SpacemiT K1 (Banana Pi F3 and Milk-V Jupiter). It
>> > > started upgrading to glibc 2.43, which does memset() through vector
>> > > instructions. It is reproducible using the Debian 7.1.7-1~bpo13+1
>> > > kernel, but I have also been able to reproduce it with a vanilla 7.2.2
>> > > kernel, using a similar configuration to the Debian kernel. The board
>> > > uses OpenSBI 1.9 and the vendor U-Boot.
>
> I have been able to also reproduce the issue with the vendor OpenSBI. It
> is also reproducible with linux 7.2.6.
>
>> > I have been able to rule out OpenSBI from the issue, I have checked
>> > there is not trap to OpenSBI when the problem happens.
>> >
>> > > Typically it manifests itself with the following kind of error, when
>> > > running g++ from GCC 16 as part of building software (e.g. OpenJDK,
>> > > Blender, Dolfin, Qt6):
>> > >
>> > > Assembler messages:
>> > > {standard input}:284588: Error: unknown pseudo-op: `.uleb1'
>> > > {standard input}:284588: Error: unrecognized opcode `ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿvl874'
>> > >
>> > > The broken chars are 0xff and it seems there are always 240 (but with
>> > > poor statistics). Sometimes it instead causes a GCC ICE instead.
>> >
>> > I have identified that the 0xff comes from the poisoning done for v0 in
>> > __riscv_v_vstate_discard(), which should only happen for a syscall.
>> > Indeed changing the value to different ones propagates to the above
>> > error message.
>> >
>> > Furthermore I have found that changing CONFIG_RISCV_ISA_V_PREEMPTIVE
>> > doesn't change anything, and that changing RISCV_ISA_V_UCOPY_THRESHOLD
>> > changes the number of broken bytes.
>>
>> The values from __riscv_v_vstate_discard() end-up there because they are
>> the last values written to the vector registers. I have added some
>> poisoning in __asm_vector_usercopy_sum_enabled before the loop, and
>> those values appear instead. Using different values per vector register,
>> I have found that the corruption comes from a partial load of the vle8.v
>> instruction, while the result of the poisoning and the partial load are
>> then both written by the vse8.v:
>>
>> loop:
>> vsetvli iVL, iNum, e8, ELEM_LMUL_SETTING, ta, ma
>> fixup vle8.v vData, (pSrc), 10f
>> sub iNum, iNum, iVL
>> add pSrc, pSrc, iVL
>> fixup vse8.v vData, (pDst), 11f
>> add pDst, pDst, iVL
>> bnez iNum, loop
>
> I have instrumented that code, basically adding a function to check the
> copy afterwards (only using scalar instructions), and report values in
> case of errors. So far I have been able to catch the issue 4 times that
> way (including one where I haven't seen any visible consequence on the
> userland).
>
> This is what I observed:
> - The issue always happens for the first bytes of the user copy, which
> in all cases were supposed to be up to 4096 bytes long.
> - On the first iteration of the loop only the first 16 bytes are loaded
> by the vle8.v instruction but the full 256 bytes are written to the
> destination by the vse8.v instrution.
That sounds like some sort of trap handling issue: something's filling
out the first word of the vector, but then not the rest, but then not
triggering a restart of the instruction. We talked some on IRC and it
sounds like that trap isn't getting into Linux, so it's possible
something in M-mode is mangling it -- this is where we start to get into
vstart/idempotent instruction territory and that's not well tested by
running on QEMU, so it wouldn't be super surprising we're just stumbling
into a bug there.
I have a K3 that I've been meaning to play around with, I'm going to go
try to see if I can get it running and reproduce this one.
> - On the second iteration of the loop, the vle8.v causes a trap, which
> ends up in the 10f fixup. At fixup level, vl=0x100, vlenb=0x20,
> vstart=0x0 and vtype=0xc3.
> - Considering the 2 first iterations of the loop (i.e. 512 bytes),
> neither the source nor destination addresses cross a page.
>
> All that said, it is what I can *observe*. I have no idea if the first
> iteration of the loop also goes through fixup or not. Also in addition
> to precise traps (which definitely happen for the second iteration), IRQ
> could happen at any moment. I use CONFIG_RISCV_ISA_V_PREEMPTIVE=n for my
> test, in order to limit the code paths to review, so during that copy
> preempt is disabled, but IRQ is not.
>
> Regards
> Aurelien
>
> --
> Aurelien Jarno GPG: 4096R/1DDD8C9B
> aurelien at aurel32.net http://aurel32.net
More information about the linux-riscv
mailing list