-
Notifications
You must be signed in to change notification settings - Fork 165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Disallow VTYPE=VILL #454
base: master
Are you sure you want to change the base?
Disallow VTYPE=VILL #454
Conversation
Philip had the following three options for changing the ABI:
This picks option 1; is there a reason behind why that's your preferred one? I can see arguments for each of them. Are we also sure that the Linux kernel is the only thing in the ecosystem setting VTYPE to be VILL on function calls? If so then that's an "easy" ABI break to deal with, but if there are other things out there then we need to know as that could change the story. I'm assuming at least that GCC, like LLVM, assumes VTYPE isn't VILL in various places and won't actively set it to that itself? |
As for my own personal opinion, I imagine that, short of changing the specification to be more helpful for software, changing the psABI in one of these ways is the least bad option. |
It was just the easiest to describe, and I didn't really see any downsides on the implementation side of things.
I'm not sure it's only Linux setting this. Library code could of course be doing anything, but setting VILL doesn't seem useful so I'm hoping that doesn't happen too much. That said, there's some language in the V spec along the lines of
which makes me worried there's unintended sets of VILL in normal-smelling code, but I'm not sure what's allowed to be unsupported. One could imagine code that tries to set some vector configuration and falls back to scalar code if the vector configuration doesn't succeed, thus leaving VILL around. As far as I can tell we're not intentionally generating code that would result in VILL from GCC, but I'm not entirely sure of that. If we did generate that code I think we'd likely just have a functional bug, though, as most instructions aren't useful under VILL. |
The main downside I can see is that the kernel would have to set VTYPE to be non-VILL for signal handlers (unless you forbid VTYPE ever being VILL whilst at least one signal is unblocked, which doesn't sound like a good idea to me). Options 2 and 3 avoid that, the function entry point itself would do it, at the expense of any function wanting to mess with vectors having to set VTYPE even if it only needs whole-register operations.
Yeah that line does sound a little concerning. I don't know enough about the vector world to have an opinion on how likely it is that's a problem, so I'll defer to your and others' experience and/or future investigations. At the end of the day, we need to form consensus between toolchain, OS and, perhaps, accelerated library developers about whether this is a reasonable ABI restriction and break to introduce. |
@palmer-dabbelt Can I ask you to spell out a couple details you mentioned offline? Specifically, how do you see an ABI change interacting with the kernel's lazy save/restore of vector state? And what is your opinion w.r.t. the existence of a kernel version which doesn't follow the new ABI variant? |
On the question of code branching on VILL, I think that is moderately unlikely. I can't think of a case where the compiler would emit such code with semantics being anything other than full UB. If the user compiled with e.g. zvl1024b and tries to run on a zvl128b machine, you'd get VILL, but also trap on the first actual vector instruction (ignore whole register move for the moment), and there would be no recovery mechanism. In terms of dynamic dispatching, the recommended answer would be to use hwprobe. It's possible that someone used VILL to do feature sniffing, but given existing hardware doesn't trap on a whole register move, it's unlikely anyone has production code which relies on that behavior. I could see them relying on trapping of e.g. a vadd.vv for feature sniffing, but the whole register move case seems unlikely. In order for the vadd.vv case (with vtype left vill) to be problematic, we'd need to have a dynamic path which did that type of feature sniffing, and then unconditionally ran a vector move anyways. The only plausible case I can think of here is code that was sniffing VLEN, and given the availability of VLENB as a register, there's far more natural ways to write that code. |
riscv-cc.adoc
Outdated
@@ -120,7 +120,8 @@ The `vxrm` and `vxsat` fields of `vcsr` are not preserved across calls and their | |||
values are unspecified upon entry. | |||
|
|||
Procedures may assume that `vstart` is zero upon entry. Procedures may assume | |||
that `vstart` is zero upon return from a procedure call. | |||
that `vstart` is zero upon return from a procedure call. Procedures may assume | |||
that `vtype` is never `VILL` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're going to retroactively change a specification (which I think we should here), we should clearly call that out in the specification text itself. (That is, acknowledge that a change was made retroactively in the text itself.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a NOTE
@palmer-dabbelt I agree with the sentiment of this proposal. How are we handling this property at syscall boundaries? I discussed this with a few folks at SiFive, and we are coming to the conclusion that, after the kernel zeroes out the state, it should set vtype to 0 (i.e. vill=0), achieving this property. It doesn't make sense to us to make userspace responsible for doing that after a syscall. |
Ya, sorry, I forgot about that -- and I think it also answers JRTC's comment about the signal handler stuff. We use The only thing that really needs to change here is how we initialize a vector context. That happens in two cases: when we trap on the first use of a vector, and when we destroy an active vector context on syscalls. Right now the uABI allows for So I think just this would be enough to do it, assuming
This would be a psABI change, strictly speaking the kernel syscall ABI is a different thing (part of the kernel uABI). That said, the rationale for the kernel syscall ABI discarding the entire vector state (including We'd have to talk about it on LKML, though, to be sure. |
Implementations are all over the place on whole register moves trapping under VILL, so let's just forbid that case in the psABI. Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com> --- We've started seeing a bunch of fallout from the "whole register moves depend on TYPE" ISA change, and there's discussion all over the place: * There's a GCC bug <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117544> * Also an LLVM bug <llvm/llvm-project#114518> * QEMU changed behavior in 4eff52cd46 ("target/riscv: Add vill check for whole vector register move instructions") * Philip has a writeup on some of the options in his notes <https://github.com/preames/public-notes/blob/master/riscv/whole-register-move-abi.rst>. * This has also come up in most of the meetings I'v been in this week. It seems like there's no general consensus on what we do here -- some discussions say we're going to change the psABI (and presumably then the uABI), some say we're not. I don't personally care a ton if we make the ABI change or not, we just need to decide so we can figure out where the bugs are -- there's going to be fallout either way, but we can't really get things fixed until we decide one way or the other. As far as I can tell both paths are valid: * If we make these ABI changes then most code that predates the ISA change continues to function correctly after the ISA change. We just need to track down anything that sets VILL and fix it, but we should be able to do that incrementally (maybe even just with a trap handler). Right now I think that's just the kernel, but I'm not 100% sure there. Looks like the first round of HW doesn't trap, though, so we should be safe for a bit. * If we don't make these ABI changes then we'll have to fix the compilers and go rebuild everything to match the ISA change. I think the GCC change should be pretty straight-forward, I don't know about the LLVM side of things. I'm not sure what we'd do with the kernel here: we could say the VILL traps are just latent userspace bugs, or we could say we're breaking userspace -- kind of a grey area, so probably more of an LKML question. I don't think one option is clearly simpler than the other, it's just a question of where we push the bugs.
@palmer-dabbelt Thanks, I think your most recent post answers my question about the kernel. |
I don't know the details of how the functions you mention fit into Linux's signal delivery flow. My concern is something like the following (excuse the pseudo-asm):
In isolation, myfunc has adhered to the ABI. However, if a signal is delivered somewhere in the region marked "here", mysighandler will, without kernel intervention, run with VTYPE=VILL. Does your proposed patch correctly deal with that case? Now this is obviously a stupid bit of code to write, but my point is that if anything ever sets VTYPE to VILL for any reason, explicitly or implicitly, even for one instruction, then the kernel must handle it. We can say that's invalid, but then that's making a stronger statement in the psABI that VTYPE can never be VILL even within a function, which generally isn't something psABIs like to do (TP, GP and sort of SP, thanks to sigaltstack, being notable exceptions). |
I'm not entirely sure, someone else (maybe @bjoto?) tracked down that last vector signal context tracking bug. I thought we initialized a new vector context for signals, but I couldn't find that in the code (though it's just a pile of hooks, so it's kind of hard to follow). So we might want something like
Though if that's the case we'd likely want it as an optimization even without the uABI change, as that state in registers isn't useful by the time userspace gets to it. |
This is still under discussion in the psABI, but it's looking like we're going to forbid VILL in userspace in order to maintain compatibility with binaries that don't expect implementations to trap whole register moves under VILL (as in QEMU before 4eff52c ("target/riscv: Add vill check for whole vector register move instructions"), for example). Fixes: f8c1f36 ("target/riscv: Set vtype.vill on CPU reset") Link: riscv-non-isa/riscv-elf-psabi-doc#454 Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
https://lore.kernel.org/qemu-devel/20241122003247.8955-1-palmer@rivosinc.com --- From: Palmer Dabbelt <palmer@rivosinc.com> To: qemu-devel@nongnu.org, qemu-riscv@nongnu.org Received-SPF: pass client-ip=2607:f8b0:4864:20::431; envelope-from=palmer@rivosinc.com; helo=mail-pf1-x431.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: <qemu-devel.nongnu.org> List-Unsubscribe: <https://lists.nongnu.org/mailman/options/qemu-devel>, <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe> List-Archive: <https://lists.nongnu.org/archive/html/qemu-devel> List-Post: <mailto:qemu-devel@nongnu.org> List-Help: <mailto:qemu-devel-request@nongnu.org?subject=help> List-Subscribe: <https://lists.nongnu.org/mailman/listinfo/qemu-devel>, <mailto:qemu-devel-request@nongnu.org?subject=subscribe> Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org This is still under discussion in the psABI, but it's looking like we're going to forbid VILL in userspace in order to maintain compatibility with binaries that don't expect implementations to trap whole register moves under VILL (as in QEMU before 4eff52c ("target/riscv: Add vill check for whole vector register move instructions"), for example). Fixes: f8c1f36 ("target/riscv: Set vtype.vill on CPU reset") Link: riscv-non-isa/riscv-elf-psabi-doc#454 Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com> --- target/riscv/cpu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index f219f0c3b5..d19a44de99 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1022,7 +1022,11 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type) cs->exception_index = RISCV_EXCP_NONE; env->load_res = -1; set_default_nan_mode(1, &env->fp_status); +#ifdef CONFIG_USER_ONLY + env->vill = false; +#else env->vill = true; +#endif #ifndef CONFIG_USER_ONLY if (cpu->cfg.debug) { -- 2.45.2 Signed-off-by: GitHub Actions Bot <bot@github.com>
After discussed with different people in the past weeks , I incline resolve that on the compiler side becasue:
Also GCC community already fix that on compiler side, LLVM community also has a proposed patch there, although LLVM community still having some concern on the performance impact, so I would keep this PR open until both compiler has addressed this issue. |
Implementations are all over the place on whole register moves trapping under VILL, so let's just forbid that case in the psABI.
Signed-off-by: Palmer Dabbelt palmer@rivosinc.com
We've started seeing a bunch of fallout from the "whole register moves depend on TYPE" ISA change, and there's discussion all over the place:
It seems like there's no general consensus on what we do here -- some discussions say we're going to change the psABI (and presumably then the uABI), some say we're not. I don't personally care a ton if we make the ABI change or not, we just need to decide so we can figure out where the bugs are -- there's going to be fallout either way, but we can't really get things fixed until we decide one way or the other. As far as I can tell both paths are valid:
I don't think one option is clearly simpler than the other, it's just a question of where we push the bugs.