The reason is the same as why RCX is not used for passing parameters to system calls, being replaced with R10 in 64-bit mode: because of how the sysenter and sysexit instructions work. Namely, from Intel docs on sysexit instruction:
Prior to executing SYSEXIT, software must specify the privilege level 3 code segment and code entry point, and the privilege level 3 stack segment and stack pointer by writing values into the following MSR and general-purpose
registers:
• IA32_SYSENTER_CS (MSR address 174H) — Contains a 32-bit value that is used to determine the segment
selectors for the privilege level 3 code and stack segments (see the Operation section)
• RDX — The canonical address in this register is loaded into RIP (thus, this value references the first instruction
to be executed in the user code). If the return is not to 64-bit mode, only bits 31:0 are loaded.
• ECX — The canonical address in this register is loaded into RSP (thus, this value contains the stack pointer for
the privilege level 3 stack). If the return is not to 64-bit mode, only bits 31:0 are loaded.
Thus rdx (edx) and rcx (ecx) are reserved by the instruction. Now what about ebp? Well, from the docs on sysenter instruction:
The SYSENTER and SYSEXIT instructions are companion instructions, but they do not constitute a call/return pair.
When executing a SYSENTER instruction, the processor does not save state information for the user code (e.g., the
instruction pointer), and neither the SYSENTER nor the SYSEXIT instruction supports passing parameters on the
stack.
This is apparent in the fact that RSP is replaced by IA32_SYSENTER_ESP on sysenter, so the OS doesn't even know where the userspace stack is supposed to be, at least this is not trivial to learn. So Linux reserves ebp exactly for this purpose: to provide the OS with the user stack. Now the caller must save ebp since it'll have to overwrite it with esp before doing sysenter.
Why didn't Linux dedicate edx or ecx for the purpose of passing stack pointer — these two registers aren't overwritten on sysenter? I think it's for speed: ebp, when used for parameter passing in usual int 0x80 calls, is the last possible (sixth) parameter. It's rare for syscalls to need more than 5 parameters, so instead of reading userspace stack for almost all system calls (if edx or ecx were used for stack pointer), Linux only has to do this for system calls with 6 parameters. (Note how you must push ebp last before doing sysenter — that's precisely because the kernel must know where to find the sixth parameter).
This all is summarized in Linux sources, arch/x86/entry/vdso/vdso32/sysenter.S:
/*
* The caller puts arg2 in %ecx, which gets pushed. The kernel will use
* %ecx itself for arg2. The pushing is because the sysexit instruction
* (found in entry.S) requires that we clobber %ecx with the desired %esp.
* User code might expect that %ecx is unclobbered though, as it would be
* for returning via the iret instruction, so we must push and pop.
*
* The caller puts arg3 in %edx, which the sysexit instruction requires
* for %eip. Thus, exactly as for arg2, we must push and pop.
*
* Arg6 is different. The caller puts arg6 in %ebp. Since the sysenter
* instruction clobbers %esp, the user's %esp won't even survive entry
* into the kernel. We store %esp in %ebp. Code in entry.S must fetch
* arg6 from the stack.
*
* You can not use this vsyscall for the clone() syscall because the
* three words on the parent stack do not get copied to the child.
*/