This is because you call the standard C function foo(). And so everything has to be saved, in case foo() nukes it.
Does the RV ABI used mandate this?
Absolutely!
Any function following the standard RISC-V ABI is free to nuke registers a0-a7, and t0-t6.
Normally in other ABIs a called function saves any registers it modifies, so he should be fine with a minimal saved set.
That is not correct:
32 bit Arm: functions are free to nuke r0-r3, r12, r14 (LR)
64 bit Arm: functions are free to nuke x0-x17, x18 (PR) if not reserved by the platform
64 bit x86: functions are free to nuke rax, rcx, rdx, rsi, rdi, r8-r11 (SysV e.g. Linux/Mac)
AVR: functions are free to nuke r0, r18-r27, r30-r31
PowerPC: functions are free to nuke r0, r3-r12
MSP430: functions are free to nuke r11-r15
Perhaps you were thinking of ancient (and inefficient) ABIs that pass arguments and function results on the stack, such as VAX, M68000, and (most) 32 bit x86 calling conventions?
I don't think any ABI designed since about 1985 requires called functions to preserve all registers.