diff mbox

KVM: arm/arm64: Access CNTHCTL_EL2 bit fields correctly

Message ID 799d03f5-a929-9547-1ae7-94026b76f116@arm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Marc Zyngier Nov. 28, 2016, 6:39 p.m. UTC
On 28/11/16 17:43, Marc Zyngier wrote:
> Hi Jintack,
> 
> On 28/11/16 16:46, Jintack Lim wrote:
>> Bit positions of CNTHCTL_EL2 are changing depending on HCR_EL2.E2H bit.
>> EL1PCEN and EL1PCTEN are 1st and 0th bits when E2H is not set, but they
>> are 11th and 10th bits respectively when E2H is set.  Current code is
>> unintentionally setting wrong bits to CNTHCTL_EL2 with E2H set, which
>> may allow guest OS to access physical timer. So, fix it.
>>
>> Signed-off-by: Jintack Lim <jintack@cs.columbia.edu>
>> ---
>>  arch/arm/include/asm/kvm_timer.h     | 33 +++++++++++++++++++
>>  arch/arm64/include/asm/kvm_timer.h   | 62 ++++++++++++++++++++++++++++++++++++
>>  include/clocksource/arm_arch_timer.h |  6 ++--
>>  virt/kvm/arm/hyp/timer-sr.c          |  8 ++---
>>  4 files changed, 103 insertions(+), 6 deletions(-)
>>  create mode 100644 arch/arm/include/asm/kvm_timer.h
>>  create mode 100644 arch/arm64/include/asm/kvm_timer.h
>>

[...]

> We could make it nicer (read "faster") by introducing a
> hyp_alternate_select construct that only returns a value instead
> of calling a function. I remember writing something like that
> at some point, and dropping it...

So here's what this could look like (warning, wacky code ahead,
though I fixed a stupid bug that was present in the previous patch).
The generated code is quite nice (no branch, only an extra mov
instruction on the default path)... Of course, completely untested!


Thanks,

	M.

Comments

Christoffer Dall Nov. 28, 2016, 7:42 p.m. UTC | #1
On Mon, Nov 28, 2016 at 06:39:04PM +0000, Marc Zyngier wrote:
> On 28/11/16 17:43, Marc Zyngier wrote:
> > Hi Jintack,
> > 
> > On 28/11/16 16:46, Jintack Lim wrote:
> >> Bit positions of CNTHCTL_EL2 are changing depending on HCR_EL2.E2H bit.
> >> EL1PCEN and EL1PCTEN are 1st and 0th bits when E2H is not set, but they
> >> are 11th and 10th bits respectively when E2H is set.  Current code is
> >> unintentionally setting wrong bits to CNTHCTL_EL2 with E2H set, which
> >> may allow guest OS to access physical timer. So, fix it.
> >>
> >> Signed-off-by: Jintack Lim <jintack@cs.columbia.edu>
> >> ---
> >>  arch/arm/include/asm/kvm_timer.h     | 33 +++++++++++++++++++
> >>  arch/arm64/include/asm/kvm_timer.h   | 62 ++++++++++++++++++++++++++++++++++++
> >>  include/clocksource/arm_arch_timer.h |  6 ++--
> >>  virt/kvm/arm/hyp/timer-sr.c          |  8 ++---
> >>  4 files changed, 103 insertions(+), 6 deletions(-)
> >>  create mode 100644 arch/arm/include/asm/kvm_timer.h
> >>  create mode 100644 arch/arm64/include/asm/kvm_timer.h
> >>
> 
> [...]
> 
> > We could make it nicer (read "faster") by introducing a
> > hyp_alternate_select construct that only returns a value instead
> > of calling a function. I remember writing something like that
> > at some point, and dropping it...
> 
> So here's what this could look like (warning, wacky code ahead,
> though I fixed a stupid bug that was present in the previous patch).
> The generated code is quite nice (no branch, only an extra mov
> instruction on the default path)... Of course, completely untested!

Isn't this all about determining which bitmask to use, statically, once,
after the system has booted?

How about a good old fashioned static variable, or global struct like
the global one we use for the VGIC, which sets the proper mit mask
during kvm init, and the world-switch code just uses a variable?

Thanks,
-Christoffer
Jintack Lim Nov. 29, 2016, 3:28 a.m. UTC | #2
On Mon, Nov 28, 2016 at 1:39 PM, Marc Zyngier <marc.zyngier@arm.com> wrote:
> On 28/11/16 17:43, Marc Zyngier wrote:
>> Hi Jintack,

Hi Marc,

>>
>> On 28/11/16 16:46, Jintack Lim wrote:
>>> Bit positions of CNTHCTL_EL2 are changing depending on HCR_EL2.E2H bit.
>>> EL1PCEN and EL1PCTEN are 1st and 0th bits when E2H is not set, but they
>>> are 11th and 10th bits respectively when E2H is set.  Current code is
>>> unintentionally setting wrong bits to CNTHCTL_EL2 with E2H set, which
>>> may allow guest OS to access physical timer. So, fix it.
>>>
>>> Signed-off-by: Jintack Lim <jintack@cs.columbia.edu>
>>> ---
>>>  arch/arm/include/asm/kvm_timer.h     | 33 +++++++++++++++++++
>>>  arch/arm64/include/asm/kvm_timer.h   | 62 ++++++++++++++++++++++++++++++++++++
>>>  include/clocksource/arm_arch_timer.h |  6 ++--
>>>  virt/kvm/arm/hyp/timer-sr.c          |  8 ++---
>>>  4 files changed, 103 insertions(+), 6 deletions(-)
>>>  create mode 100644 arch/arm/include/asm/kvm_timer.h
>>>  create mode 100644 arch/arm64/include/asm/kvm_timer.h
>>>
>
> [...]
>
>> We could make it nicer (read "faster") by introducing a
>> hyp_alternate_select construct that only returns a value instead
>> of calling a function. I remember writing something like that
>> at some point, and dropping it...
>
> So here's what this could look like (warning, wacky code ahead,
> though I fixed a stupid bug that was present in the previous patch).
> The generated code is quite nice (no branch, only an extra mov
> instruction on the default path)... Of course, completely untested!

This looks much cleaner than my patch.
While we are at it, is it worth to consider that we just need to set
those bits once for VHE case, not for every world switch as an
optimization?

>
> diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> index b18e852..d173902 100644
> --- a/arch/arm64/include/asm/kvm_hyp.h
> +++ b/arch/arm64/include/asm/kvm_hyp.h
> @@ -121,6 +121,17 @@ typeof(orig) * __hyp_text fname(void)                                      \
>         return val;                                                     \
>  }
>
> +#define hyp_alternate_select_const(fname, orig, alt, cond)             \
> +inline const typeof(orig) __hyp_text fname(void)                       \
> +{                                                                      \
> +       typeof(alt) val = orig;                                         \
> +       asm volatile(ALTERNATIVE("nop           \n",                    \
> +                                "mov   %0, %1  \n",                    \
> +                                cond)                                  \
> +                    : "+r" (val) : "r" (alt));                         \
> +       return val;                                                     \
> +}
> +
>  void __vgic_v2_save_state(struct kvm_vcpu *vcpu);
>  void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
>  int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
> diff --git a/virt/kvm/arm/hyp/timer-sr.c b/virt/kvm/arm/hyp/timer-sr.c
> index 798866a..7a783af 100644
> --- a/virt/kvm/arm/hyp/timer-sr.c
> +++ b/virt/kvm/arm/hyp/timer-sr.c
> @@ -21,11 +21,29 @@
>
>  #include <asm/kvm_hyp.h>
>
> +#ifdef CONFIG_ARM64
> +static hyp_alternate_select_const(cnthclt_shift, 0, 10,
> +                                 ARM64_HAS_VIRT_HOST_EXTN)
> +
> +#else
> +#define cnthclt_shift()                (0)
> +#endif
> +
> +static inline void __hyp_text cnthctl_rmw(u32 clr, u32 set)
> +{
> +       u32 val;
> +       int shift = cnthclt_shift();
> +
> +       val = read_sysreg(cnthctl_el2);
> +       val &= ~(clr << shift);
> +       val |= set << shift;
> +       write_sysreg(val, cnthctl_el2);
> +}
> +
>  /* vcpu is already in the HYP VA space */
>  void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu)
>  {
>         struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> -       u64 val;
>
>         if (timer->enabled) {
>                 timer->cntv_ctl = read_sysreg_el0(cntv_ctl);
> @@ -36,9 +54,7 @@ void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu)
>         write_sysreg_el0(0, cntv_ctl);
>
>         /* Allow physical timer/counter access for the host */
> -       val = read_sysreg(cnthctl_el2);
> -       val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
> -       write_sysreg(val, cnthctl_el2);
> +       cnthctl_rmw(0, CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN);
>
>         /* Clear cntvoff for the host */
>         write_sysreg(0, cntvoff_el2);
> @@ -48,16 +64,12 @@ void __hyp_text __timer_restore_state(struct kvm_vcpu *vcpu)
>  {
>         struct kvm *kvm = kern_hyp_va(vcpu->kvm);
>         struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> -       u64 val;
>
>         /*
>          * Disallow physical timer access for the guest
>          * Physical counter access is allowed
>          */
> -       val = read_sysreg(cnthctl_el2);
> -       val &= ~CNTHCTL_EL1PCEN;
> -       val |= CNTHCTL_EL1PCTEN;
> -       write_sysreg(val, cnthctl_el2);
> +       cnthctl_rmw(CNTHCTL_EL1PCEN, CNTHCTL_EL1PCTEN);
>
>         if (timer->enabled) {
>                 write_sysreg(kvm->arch.timer.cntvoff, cntvoff_el2);
>
> Thanks,
>
>         M.
> --
> Jazz is not dead. It just smells funny...
>
Marc Zyngier Nov. 29, 2016, 9:36 a.m. UTC | #3
On 29/11/16 03:28, Jintack Lim wrote:
> On Mon, Nov 28, 2016 at 1:39 PM, Marc Zyngier <marc.zyngier@arm.com> wrote:
>> On 28/11/16 17:43, Marc Zyngier wrote:
>>> Hi Jintack,
> 
> Hi Marc,
> 
>>>
>>> On 28/11/16 16:46, Jintack Lim wrote:
>>>> Bit positions of CNTHCTL_EL2 are changing depending on HCR_EL2.E2H bit.
>>>> EL1PCEN and EL1PCTEN are 1st and 0th bits when E2H is not set, but they
>>>> are 11th and 10th bits respectively when E2H is set.  Current code is
>>>> unintentionally setting wrong bits to CNTHCTL_EL2 with E2H set, which
>>>> may allow guest OS to access physical timer. So, fix it.
>>>>
>>>> Signed-off-by: Jintack Lim <jintack@cs.columbia.edu>
>>>> ---
>>>>  arch/arm/include/asm/kvm_timer.h     | 33 +++++++++++++++++++
>>>>  arch/arm64/include/asm/kvm_timer.h   | 62 ++++++++++++++++++++++++++++++++++++
>>>>  include/clocksource/arm_arch_timer.h |  6 ++--
>>>>  virt/kvm/arm/hyp/timer-sr.c          |  8 ++---
>>>>  4 files changed, 103 insertions(+), 6 deletions(-)
>>>>  create mode 100644 arch/arm/include/asm/kvm_timer.h
>>>>  create mode 100644 arch/arm64/include/asm/kvm_timer.h
>>>>
>>
>> [...]
>>
>>> We could make it nicer (read "faster") by introducing a
>>> hyp_alternate_select construct that only returns a value instead
>>> of calling a function. I remember writing something like that
>>> at some point, and dropping it...
>>
>> So here's what this could look like (warning, wacky code ahead,
>> though I fixed a stupid bug that was present in the previous patch).
>> The generated code is quite nice (no branch, only an extra mov
>> instruction on the default path)... Of course, completely untested!
> 
> This looks much cleaner than my patch.
> While we are at it, is it worth to consider that we just need to set
> those bits once for VHE case, not for every world switch as an
> optimization?

Ah! That's a much better idea indeed! And we could stop messing with
cntvoff_el2 as well, as it doesn't need to be restored to zero on exit.
Could you try and respin something along those lines?

Thanks,

	M.
Marc Zyngier Nov. 29, 2016, 9:37 a.m. UTC | #4
On 28/11/16 19:42, Christoffer Dall wrote:
> On Mon, Nov 28, 2016 at 06:39:04PM +0000, Marc Zyngier wrote:
>> On 28/11/16 17:43, Marc Zyngier wrote:
>>> Hi Jintack,
>>>
>>> On 28/11/16 16:46, Jintack Lim wrote:
>>>> Bit positions of CNTHCTL_EL2 are changing depending on HCR_EL2.E2H bit.
>>>> EL1PCEN and EL1PCTEN are 1st and 0th bits when E2H is not set, but they
>>>> are 11th and 10th bits respectively when E2H is set.  Current code is
>>>> unintentionally setting wrong bits to CNTHCTL_EL2 with E2H set, which
>>>> may allow guest OS to access physical timer. So, fix it.
>>>>
>>>> Signed-off-by: Jintack Lim <jintack@cs.columbia.edu>
>>>> ---
>>>>  arch/arm/include/asm/kvm_timer.h     | 33 +++++++++++++++++++
>>>>  arch/arm64/include/asm/kvm_timer.h   | 62 ++++++++++++++++++++++++++++++++++++
>>>>  include/clocksource/arm_arch_timer.h |  6 ++--
>>>>  virt/kvm/arm/hyp/timer-sr.c          |  8 ++---
>>>>  4 files changed, 103 insertions(+), 6 deletions(-)
>>>>  create mode 100644 arch/arm/include/asm/kvm_timer.h
>>>>  create mode 100644 arch/arm64/include/asm/kvm_timer.h
>>>>
>>
>> [...]
>>
>>> We could make it nicer (read "faster") by introducing a
>>> hyp_alternate_select construct that only returns a value instead
>>> of calling a function. I remember writing something like that
>>> at some point, and dropping it...
>>
>> So here's what this could look like (warning, wacky code ahead,
>> though I fixed a stupid bug that was present in the previous patch).
>> The generated code is quite nice (no branch, only an extra mov
>> instruction on the default path)... Of course, completely untested!
> 
> Isn't this all about determining which bitmask to use, statically, once,
> after the system has booted?
> 
> How about a good old fashioned static variable, or global struct like
> the global one we use for the VGIC, which sets the proper mit mask
> during kvm init, and the world-switch code just uses a variable?

We could indeed do that (I've been carried away with my tendency for
weird and wonderful hacks).

But as Jintack mentioned, there is a much better approach, which is to
do nothing at all on the VHE path (we can set the permission bits once
and for all). cntvoff_el2 also falls into the same category of things we
should be able to only restore and not bother resetting (as it doesn't
affect the EL2 virtual counter).

Thoughts?

	M.
Christoffer Dall Nov. 29, 2016, 10:47 a.m. UTC | #5
On Tue, Nov 29, 2016 at 09:37:07AM +0000, Marc Zyngier wrote:
> On 28/11/16 19:42, Christoffer Dall wrote:
> > On Mon, Nov 28, 2016 at 06:39:04PM +0000, Marc Zyngier wrote:
> >> On 28/11/16 17:43, Marc Zyngier wrote:
> >>> Hi Jintack,
> >>>
> >>> On 28/11/16 16:46, Jintack Lim wrote:
> >>>> Bit positions of CNTHCTL_EL2 are changing depending on HCR_EL2.E2H bit.
> >>>> EL1PCEN and EL1PCTEN are 1st and 0th bits when E2H is not set, but they
> >>>> are 11th and 10th bits respectively when E2H is set.  Current code is
> >>>> unintentionally setting wrong bits to CNTHCTL_EL2 with E2H set, which
> >>>> may allow guest OS to access physical timer. So, fix it.
> >>>>
> >>>> Signed-off-by: Jintack Lim <jintack@cs.columbia.edu>
> >>>> ---
> >>>>  arch/arm/include/asm/kvm_timer.h     | 33 +++++++++++++++++++
> >>>>  arch/arm64/include/asm/kvm_timer.h   | 62 ++++++++++++++++++++++++++++++++++++
> >>>>  include/clocksource/arm_arch_timer.h |  6 ++--
> >>>>  virt/kvm/arm/hyp/timer-sr.c          |  8 ++---
> >>>>  4 files changed, 103 insertions(+), 6 deletions(-)
> >>>>  create mode 100644 arch/arm/include/asm/kvm_timer.h
> >>>>  create mode 100644 arch/arm64/include/asm/kvm_timer.h
> >>>>
> >>
> >> [...]
> >>
> >>> We could make it nicer (read "faster") by introducing a
> >>> hyp_alternate_select construct that only returns a value instead
> >>> of calling a function. I remember writing something like that
> >>> at some point, and dropping it...
> >>
> >> So here's what this could look like (warning, wacky code ahead,
> >> though I fixed a stupid bug that was present in the previous patch).
> >> The generated code is quite nice (no branch, only an extra mov
> >> instruction on the default path)... Of course, completely untested!
> > 
> > Isn't this all about determining which bitmask to use, statically, once,
> > after the system has booted?
> > 
> > How about a good old fashioned static variable, or global struct like
> > the global one we use for the VGIC, which sets the proper mit mask
> > during kvm init, and the world-switch code just uses a variable?
> 
> We could indeed do that (I've been carried away with my tendency for
> weird and wonderful hacks).
> 
> But as Jintack mentioned, there is a much better approach, which is to
> do nothing at all on the VHE path (we can set the permission bits once
> and for all). cntvoff_el2 also falls into the same category of things we
> should be able to only restore and not bother resetting (as it doesn't
> affect the EL2 virtual counter).
> 
> Thoughts?
> 
Yes, that sounds much better.

I have some patches to get rid of a lot of things, like cntvoff, during
the world-switch for VHE, so if Jintack just wants to focus on the
cnthctl I will catch cntvoff later.

-Christoffer
Marc Zyngier Nov. 29, 2016, 10:53 a.m. UTC | #6
On 29/11/16 10:47, Christoffer Dall wrote:
> On Tue, Nov 29, 2016 at 09:37:07AM +0000, Marc Zyngier wrote:
>> On 28/11/16 19:42, Christoffer Dall wrote:
>>> On Mon, Nov 28, 2016 at 06:39:04PM +0000, Marc Zyngier wrote:
>>>> On 28/11/16 17:43, Marc Zyngier wrote:
>>>>> Hi Jintack,
>>>>>
>>>>> On 28/11/16 16:46, Jintack Lim wrote:
>>>>>> Bit positions of CNTHCTL_EL2 are changing depending on HCR_EL2.E2H bit.
>>>>>> EL1PCEN and EL1PCTEN are 1st and 0th bits when E2H is not set, but they
>>>>>> are 11th and 10th bits respectively when E2H is set.  Current code is
>>>>>> unintentionally setting wrong bits to CNTHCTL_EL2 with E2H set, which
>>>>>> may allow guest OS to access physical timer. So, fix it.
>>>>>>
>>>>>> Signed-off-by: Jintack Lim <jintack@cs.columbia.edu>
>>>>>> ---
>>>>>>  arch/arm/include/asm/kvm_timer.h     | 33 +++++++++++++++++++
>>>>>>  arch/arm64/include/asm/kvm_timer.h   | 62 ++++++++++++++++++++++++++++++++++++
>>>>>>  include/clocksource/arm_arch_timer.h |  6 ++--
>>>>>>  virt/kvm/arm/hyp/timer-sr.c          |  8 ++---
>>>>>>  4 files changed, 103 insertions(+), 6 deletions(-)
>>>>>>  create mode 100644 arch/arm/include/asm/kvm_timer.h
>>>>>>  create mode 100644 arch/arm64/include/asm/kvm_timer.h
>>>>>>
>>>>
>>>> [...]
>>>>
>>>>> We could make it nicer (read "faster") by introducing a
>>>>> hyp_alternate_select construct that only returns a value instead
>>>>> of calling a function. I remember writing something like that
>>>>> at some point, and dropping it...
>>>>
>>>> So here's what this could look like (warning, wacky code ahead,
>>>> though I fixed a stupid bug that was present in the previous patch).
>>>> The generated code is quite nice (no branch, only an extra mov
>>>> instruction on the default path)... Of course, completely untested!
>>>
>>> Isn't this all about determining which bitmask to use, statically, once,
>>> after the system has booted?
>>>
>>> How about a good old fashioned static variable, or global struct like
>>> the global one we use for the VGIC, which sets the proper mit mask
>>> during kvm init, and the world-switch code just uses a variable?
>>
>> We could indeed do that (I've been carried away with my tendency for
>> weird and wonderful hacks).
>>
>> But as Jintack mentioned, there is a much better approach, which is to
>> do nothing at all on the VHE path (we can set the permission bits once
>> and for all). cntvoff_el2 also falls into the same category of things we
>> should be able to only restore and not bother resetting (as it doesn't
>> affect the EL2 virtual counter).
>>
>> Thoughts?
>>
> Yes, that sounds much better.
> 
> I have some patches to get rid of a lot of things, like cntvoff, during
> the world-switch for VHE, so if Jintack just wants to focus on the
> cnthctl I will catch cntvoff later.

Sound good to me.

Thanks,

	M.
Jintack Lim Nov. 29, 2016, 11:29 a.m. UTC | #7
On Tue, Nov 29, 2016 at 4:36 AM, Marc Zyngier <marc.zyngier@arm.com> wrote:
> On 29/11/16 03:28, Jintack Lim wrote:
>> On Mon, Nov 28, 2016 at 1:39 PM, Marc Zyngier <marc.zyngier@arm.com> wrote:
>>> On 28/11/16 17:43, Marc Zyngier wrote:
>>>> Hi Jintack,
>>
>> Hi Marc,
>>
>>>>
>>>> On 28/11/16 16:46, Jintack Lim wrote:
>>>>> Bit positions of CNTHCTL_EL2 are changing depending on HCR_EL2.E2H bit.
>>>>> EL1PCEN and EL1PCTEN are 1st and 0th bits when E2H is not set, but they
>>>>> are 11th and 10th bits respectively when E2H is set.  Current code is
>>>>> unintentionally setting wrong bits to CNTHCTL_EL2 with E2H set, which
>>>>> may allow guest OS to access physical timer. So, fix it.
>>>>>
>>>>> Signed-off-by: Jintack Lim <jintack@cs.columbia.edu>
>>>>> ---
>>>>>  arch/arm/include/asm/kvm_timer.h     | 33 +++++++++++++++++++
>>>>>  arch/arm64/include/asm/kvm_timer.h   | 62 ++++++++++++++++++++++++++++++++++++
>>>>>  include/clocksource/arm_arch_timer.h |  6 ++--
>>>>>  virt/kvm/arm/hyp/timer-sr.c          |  8 ++---
>>>>>  4 files changed, 103 insertions(+), 6 deletions(-)
>>>>>  create mode 100644 arch/arm/include/asm/kvm_timer.h
>>>>>  create mode 100644 arch/arm64/include/asm/kvm_timer.h
>>>>>
>>>
>>> [...]
>>>
>>>> We could make it nicer (read "faster") by introducing a
>>>> hyp_alternate_select construct that only returns a value instead
>>>> of calling a function. I remember writing something like that
>>>> at some point, and dropping it...
>>>
>>> So here's what this could look like (warning, wacky code ahead,
>>> though I fixed a stupid bug that was present in the previous patch).
>>> The generated code is quite nice (no branch, only an extra mov
>>> instruction on the default path)... Of course, completely untested!
>>
>> This looks much cleaner than my patch.
>> While we are at it, is it worth to consider that we just need to set
>> those bits once for VHE case, not for every world switch as an
>> optimization?
>
> Ah! That's a much better idea indeed! And we could stop messing with
> cntvoff_el2 as well, as it doesn't need to be restored to zero on exit.
> Could you try and respin something along those lines?

Yes, I can.

Thanks,
Jintack

>
> Thanks,
>
>         M.
> --
> Jazz is not dead. It just smells funny...
>
Suzuki K Poulose Nov. 29, 2016, 4:53 p.m. UTC | #8
On 29/11/16 09:36, Marc Zyngier wrote:
> On 29/11/16 03:28, Jintack Lim wrote:
>> On Mon, Nov 28, 2016 at 1:39 PM, Marc Zyngier <marc.zyngier@arm.com> wrote:
>>> On 28/11/16 17:43, Marc Zyngier wrote:
>> This looks much cleaner than my patch.
>> While we are at it, is it worth to consider that we just need to set
>> those bits once for VHE case, not for every world switch as an
>> optimization?
>
> Ah! That's a much better idea indeed! And we could stop messing with
> cntvoff_el2 as well, as it doesn't need to be restored to zero on exit.
> Could you try and respin something along those lines?
>

fyi, we have a static_key based cpus_have_const_cap() for Constant cap
checking (like this case) available in linux-next. May be you could make use
of that instead of alternatives.


Cheers
Suzuki
Jintack Lim Nov. 29, 2016, 9:05 p.m. UTC | #9
On Tue, Nov 29, 2016 at 11:53 AM, Suzuki K Poulose
<suzuki.poulose@arm.com> wrote:
> On 29/11/16 09:36, Marc Zyngier wrote:
>>
>> On 29/11/16 03:28, Jintack Lim wrote:
>>>
>>> On Mon, Nov 28, 2016 at 1:39 PM, Marc Zyngier <marc.zyngier@arm.com>
>>> wrote:
>>>>
>>>> On 28/11/16 17:43, Marc Zyngier wrote:
>>>
>>> This looks much cleaner than my patch.
>>> While we are at it, is it worth to consider that we just need to set
>>> those bits once for VHE case, not for every world switch as an
>>> optimization?
>>
>>
>> Ah! That's a much better idea indeed! And we could stop messing with
>> cntvoff_el2 as well, as it doesn't need to be restored to zero on exit.
>> Could you try and respin something along those lines?
>>
>
> fyi, we have a static_key based cpus_have_const_cap() for Constant cap
> checking (like this case) available in linux-next. May be you could make use
> of that instead of alternatives.

Thanks Suzuki. This looks very useful.

Marc, can I write a patch based on linux-next? The commit which has
cpus_have_const_cap() is not in master and next branch in kvm/arm
repo.

>
>
> Cheers
> Suzuki
>
Marc Zyngier Nov. 30, 2016, 1:31 p.m. UTC | #10
On 29/11/16 21:05, Jintack Lim wrote:
> On Tue, Nov 29, 2016 at 11:53 AM, Suzuki K Poulose
> <suzuki.poulose@arm.com> wrote:
>> On 29/11/16 09:36, Marc Zyngier wrote:
>>>
>>> On 29/11/16 03:28, Jintack Lim wrote:
>>>>
>>>> On Mon, Nov 28, 2016 at 1:39 PM, Marc Zyngier <marc.zyngier@arm.com>
>>>> wrote:
>>>>>
>>>>> On 28/11/16 17:43, Marc Zyngier wrote:
>>>>
>>>> This looks much cleaner than my patch.
>>>> While we are at it, is it worth to consider that we just need to set
>>>> those bits once for VHE case, not for every world switch as an
>>>> optimization?
>>>
>>>
>>> Ah! That's a much better idea indeed! And we could stop messing with
>>> cntvoff_el2 as well, as it doesn't need to be restored to zero on exit.
>>> Could you try and respin something along those lines?
>>>
>>
>> fyi, we have a static_key based cpus_have_const_cap() for Constant cap
>> checking (like this case) available in linux-next. May be you could make use
>> of that instead of alternatives.
> 
> Thanks Suzuki. This looks very useful.
> 
> Marc, can I write a patch based on linux-next? The commit which has
> cpus_have_const_cap() is not in master and next branch in kvm/arm
> repo.

You can. It is just that I won't be able to apply it immediately (I'll
wait for -rc1 to be out, and send it as a fix).

Thanks,

	M.
Jintack Lim Nov. 30, 2016, 1:41 p.m. UTC | #11
On Wed, Nov 30, 2016 at 8:31 AM, Marc Zyngier <marc.zyngier@arm.com> wrote:
> On 29/11/16 21:05, Jintack Lim wrote:
>> On Tue, Nov 29, 2016 at 11:53 AM, Suzuki K Poulose
>> <suzuki.poulose@arm.com> wrote:
>>> On 29/11/16 09:36, Marc Zyngier wrote:
>>>>
>>>> On 29/11/16 03:28, Jintack Lim wrote:
>>>>>
>>>>> On Mon, Nov 28, 2016 at 1:39 PM, Marc Zyngier <marc.zyngier@arm.com>
>>>>> wrote:
>>>>>>
>>>>>> On 28/11/16 17:43, Marc Zyngier wrote:
>>>>>
>>>>> This looks much cleaner than my patch.
>>>>> While we are at it, is it worth to consider that we just need to set
>>>>> those bits once for VHE case, not for every world switch as an
>>>>> optimization?
>>>>
>>>>
>>>> Ah! That's a much better idea indeed! And we could stop messing with
>>>> cntvoff_el2 as well, as it doesn't need to be restored to zero on exit.
>>>> Could you try and respin something along those lines?
>>>>
>>>
>>> fyi, we have a static_key based cpus_have_const_cap() for Constant cap
>>> checking (like this case) available in linux-next. May be you could make use
>>> of that instead of alternatives.
>>
>> Thanks Suzuki. This looks very useful.
>>
>> Marc, can I write a patch based on linux-next? The commit which has
>> cpus_have_const_cap() is not in master and next branch in kvm/arm
>> repo.
>
> You can. It is just that I won't be able to apply it immediately (I'll
> wait for -rc1 to be out, and send it as a fix).

Ok. Thanks!. I'll send out v2.

>
> Thanks,
>
>         M.
> --
> Jazz is not dead. It just smells funny...
>
diff mbox

Patch

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index b18e852..d173902 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -121,6 +121,17 @@  typeof(orig) * __hyp_text fname(void)					\
 	return val;							\
 }
 
+#define hyp_alternate_select_const(fname, orig, alt, cond)		\
+inline const typeof(orig) __hyp_text fname(void)			\
+{									\
+	typeof(alt) val = orig;						\
+	asm volatile(ALTERNATIVE("nop		\n",			\
+				 "mov	%0, %1	\n",			\
+				 cond)					\
+		     : "+r" (val) : "r" (alt));				\
+	return val;							\
+}
+
 void __vgic_v2_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
 int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
diff --git a/virt/kvm/arm/hyp/timer-sr.c b/virt/kvm/arm/hyp/timer-sr.c
index 798866a..7a783af 100644
--- a/virt/kvm/arm/hyp/timer-sr.c
+++ b/virt/kvm/arm/hyp/timer-sr.c
@@ -21,11 +21,29 @@ 
 
 #include <asm/kvm_hyp.h>
 
+#ifdef CONFIG_ARM64
+static hyp_alternate_select_const(cnthclt_shift, 0, 10,
+				  ARM64_HAS_VIRT_HOST_EXTN)
+
+#else
+#define cnthclt_shift()		(0)
+#endif
+
+static inline void __hyp_text cnthctl_rmw(u32 clr, u32 set)
+{
+	u32 val;
+	int shift = cnthclt_shift();
+
+	val = read_sysreg(cnthctl_el2);
+	val &= ~(clr << shift);
+	val |= set << shift;
+	write_sysreg(val, cnthctl_el2);
+}
+
 /* vcpu is already in the HYP VA space */
 void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
-	u64 val;
 
 	if (timer->enabled) {
 		timer->cntv_ctl = read_sysreg_el0(cntv_ctl);
@@ -36,9 +54,7 @@  void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu)
 	write_sysreg_el0(0, cntv_ctl);
 
 	/* Allow physical timer/counter access for the host */
-	val = read_sysreg(cnthctl_el2);
-	val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
-	write_sysreg(val, cnthctl_el2);
+	cnthctl_rmw(0, CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN);
 
 	/* Clear cntvoff for the host */
 	write_sysreg(0, cntvoff_el2);
@@ -48,16 +64,12 @@  void __hyp_text __timer_restore_state(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = kern_hyp_va(vcpu->kvm);
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
-	u64 val;
 
 	/*
 	 * Disallow physical timer access for the guest
 	 * Physical counter access is allowed
 	 */
-	val = read_sysreg(cnthctl_el2);
-	val &= ~CNTHCTL_EL1PCEN;
-	val |= CNTHCTL_EL1PCTEN;
-	write_sysreg(val, cnthctl_el2);
+	cnthctl_rmw(CNTHCTL_EL1PCEN, CNTHCTL_EL1PCTEN);
 
 	if (timer->enabled) {
 		write_sysreg(kvm->arch.timer.cntvoff, cntvoff_el2);