On Fri, Mar 08, 2024 at 05:54:20PM +0000, Marc Zyngier wrote: > On Fri, 08 Mar 2024 17:20:59 +0000, > Joey Gouly <joey.gouly@xxxxxxx> wrote: > > > > Phew.. > > [...] > > > Each function in this file is quite small, but there's certainly a lot of > > complexity and background knowledge required to understand them! > > > > I spent quite some time on each part to see if it matches what I understood > > from the Arm ARM. > > > > Reviewed-by: Joey Gouly <joey.gouly@xxxxxxx> > > Thanks a lot for putting up with it, much appreciated. > > > A side note / thing I considered. KVM doesn't currently handle ERET exceptions > > from EL1. > > EL1 is ambiguous here. Is that EL1 from the PoV of the guest? Yes I meant an EL1 guest (not vEL2). > > > > > 1. If an ERETA{A,B} were executed from a nested EL1 guest, that would be > > trapped up to Host KVM at EL2. > > There are two possibilities for that (assuming EL1 from the PoV of a > L1 guest): > > (1) this EL1 guest is itself a guest hypervisor (i.e. we are running > an L1 guest which itself is using NV and running an L2 which > itself is a hypervisor). In that case, ERET* would have to be > trapped to EL2 and re-injected. Note that we do not support NV > under NV. Yet... > > (2) the L2 guest is not a hypervisor (no recursive NV), but the L1 > hypervisor has set HFGITR_EL2.ERET==1. We'd have to re-inject the > exception into L1, just like in the precedent case. > > If neither HCR_EL2.NV nor HFGITR_EL2.ERET are set, then no ERET* gets > trapped at all. Crucially, when running an L2 guest that doesn't isn't > itself a hypervisor (no nested NV), we do not trap ERET* at all. That was the missing part. __compute_hcr() only adds HCR_EL2.NV when is_hyp_ctxt() is true. When I conjured up this scenario, I had HCR_EL2.NV set (in my head) for the L2 EL1 guest, which is not the case. > > In a way, the NV overhead is mostly when running L1. Once you run L2, > the overhead "vanishes", to some extent (as long as you don't exit, > because that's where the cost is). > > > 2. kvm_hyp_handle_eret() returns false since it's not from vEL2. Inside > > kvm_handle_eret(), is_hyp_ctxt() is false so the exception is injected into > > vEL2 (via kvm_inject_nested_sync()). > > > > 3. vEL2 gets the exception, kvm_hyp_handle_eret() returns false as before. > > Inside kvm_handle_eret(), is_hyp_ctxt() is also false, so > > kvm_inject_nested_sync() is called but now errors out since vcpu_has_nv() is > > false. > > > > Is that flow right? Am I missing something? > > I'm not sure. The cases where ERET gets trapped are really limited to > the above two cases. > Thanks for the explanation, Joey