Re: Migration with directly assigned devices is possible?

2018-04-24 Thread Jintack Lim
On Tue, Apr 24, 2018 at 1:13 PM, Paolo Bonzini <pbonz...@redhat.com> wrote:
> On 24/04/2018 16:56, Jintack Lim wrote:
>> Hi,
>>
>> I wonder if we can do migration with directly assigned devices (i.e.
>> pass-through devices)? I looked at the KVM migration page[1], but
>> couldn't find information. Can somebody let me now if it's possible or
>> point me the related documents?
>
> No, it's not possible.  Various device-specific methods have been
> proposed, but none has ever been included into either VFIO or QEMU.
>

Thanks for letting me know, Paolo!!

Best,
Jintack

> Thanks,
>
> Paolo
>

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Migration with directly assigned devices is possible?

2018-04-24 Thread Jintack Lim
Hi,

I wonder if we can do migration with directly assigned devices (i.e.
pass-through devices)? I looked at the KVM migration page[1], but
couldn't find information. Can somebody let me now if it's possible or
point me the related documents?

Thanks,
Jintack


[1] https://www.linux-kvm.org/page/Migration

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [PATCH] KVM: arm/arm64: Don't enable/disable physical timer access on VHE

2017-11-20 Thread Jintack Lim
On Mon, Nov 20, 2017 at 6:16 AM, Christoffer Dall
<christoffer.d...@linaro.org> wrote:
> After the timer optimization rework we accidentally end up calling
> physical timer enable/disable functions on VHE systems, which is neither
> needed nor correct, since the CNTHCTL_EL2 register format is
> different when HCR_EL2.E2H is set.
>
> The CNTHCTL_EL2 is initialized when CPUs become online in
> kvm_timer_init_vhe() and we don't have to call these functions on VHE
> systems, which also allows us to inline the non-VHE functionality.
>
> Reported-by: Jintack Lim <jint...@cs.columbia.edu>
> Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>

Reviewed-by: Jintack Lim <jint...@cs.columbia.edu>

Thanks,
Jintack

> ---
>  include/kvm/arm_arch_timer.h |  3 ---
>  virt/kvm/arm/arch_timer.c|  6 --
>  virt/kvm/arm/hyp/timer-sr.c  | 48 
> ++--
>  3 files changed, 20 insertions(+), 37 deletions(-)
>
> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> index 01ee473517e2..6e45608b2399 100644
> --- a/include/kvm/arm_arch_timer.h
> +++ b/include/kvm/arm_arch_timer.h
> @@ -93,7 +93,4 @@ void kvm_timer_init_vhe(void);
>  #define vcpu_vtimer(v) (&(v)->arch.timer_cpu.vtimer)
>  #define vcpu_ptimer(v) (&(v)->arch.timer_cpu.ptimer)
>
> -void enable_el1_phys_timer_access(void);
> -void disable_el1_phys_timer_access(void);
> -
>  #endif
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index 4151250ce8da..190c99ed1b73 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -479,9 +479,6 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
>
> vtimer_restore_state(vcpu);
>
> -   if (has_vhe())
> -   disable_el1_phys_timer_access();
> -
> /* Set the background timer for the physical timer emulation. */
> phys_timer_emulate(vcpu);
>  }
> @@ -510,9 +507,6 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
> if (unlikely(!timer->enabled))
> return;
>
> -   if (has_vhe())
> -   enable_el1_phys_timer_access();
> -
> vtimer_save_state(vcpu);
>
> /*
> diff --git a/virt/kvm/arm/hyp/timer-sr.c b/virt/kvm/arm/hyp/timer-sr.c
> index f39861639f08..f24404b3c8df 100644
> --- a/virt/kvm/arm/hyp/timer-sr.c
> +++ b/virt/kvm/arm/hyp/timer-sr.c
> @@ -27,42 +27,34 @@ void __hyp_text __kvm_timer_set_cntvoff(u32 cntvoff_low, 
> u32 cntvoff_high)
> write_sysreg(cntvoff, cntvoff_el2);
>  }
>
> -void __hyp_text enable_el1_phys_timer_access(void)
> -{
> -   u64 val;
> -
> -   /* Allow physical timer/counter access for the host */
> -   val = read_sysreg(cnthctl_el2);
> -   val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
> -   write_sysreg(val, cnthctl_el2);
> -}
> -
> -void __hyp_text disable_el1_phys_timer_access(void)
> -{
> -   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);
> -}
> -
>  void __hyp_text __timer_disable_traps(struct kvm_vcpu *vcpu)
>  {
> /*
>  * We don't need to do this for VHE since the host kernel runs in EL2
>  * with HCR_EL2.TGE ==1, which makes those bits have no impact.
>  */
> -   if (!has_vhe())
> -   enable_el1_phys_timer_access();
> +   if (!has_vhe()) {
> +   u64 val;
> +
> +   /* Allow physical timer/counter access for the host */
> +   val = read_sysreg(cnthctl_el2);
> +   val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
> +   write_sysreg(val, cnthctl_el2);
> +   }
>  }
>
>  void __hyp_text __timer_enable_traps(struct kvm_vcpu *vcpu)
>  {
> -   if (!has_vhe())
> -   disable_el1_phys_timer_access();
> +   if (!has_vhe()) {
> +   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);
> +   }
>  }
> --
> 2.14.2
>
>

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [PATCH v4 14/20] KVM: arm/arm64: Avoid timer save/restore in vcpu entry/exit

2017-11-20 Thread Jintack Lim
On Mon, Nov 20, 2017 at 6:15 AM, Christoffer Dall <cd...@linaro.org> wrote:
> On Thu, Nov 16, 2017 at 03:30:39PM -0500, Jintack Lim wrote:
>> Hi Christoffer,
>>
>> On Fri, Oct 20, 2017 at 7:49 AM, Christoffer Dall
>> <christoffer.d...@linaro.org> wrote:
>> > From: Christoffer Dall <cd...@linaro.org>
>> >
>> > We don't need to save and restore the hardware timer state and examine
>> > if it generates interrupts on on every entry/exit to the guest.  The
>> > timer hardware is perfectly capable of telling us when it has expired
>> > by signaling interrupts.
>> >
>> > When taking a vtimer interrupt in the host, we don't want to mess with
>> > the timer configuration, we just want to forward the physical interrupt
>> > to the guest as a virtual interrupt.  We can use the split priority drop
>> > and deactivate feature of the GIC to do this, which leaves an EOI'ed
>> > interrupt active on the physical distributor, making sure we don't keep
>> > taking timer interrupts which would prevent the guest from running.  We
>> > can then forward the physical interrupt to the VM using the HW bit in
>> > the LR of the GIC, like we do already, which lets the guest directly
>> > deactivate both the physical and virtual timer simultaneously, allowing
>> > the timer hardware to exit the VM and generate a new physical interrupt
>> > when the timer output is again asserted later on.
>> >
>> > We do need to capture this state when migrating VCPUs between physical
>> > CPUs, however, which we use the vcpu put/load functions for, which are
>> > called through preempt notifiers whenever the thread is scheduled away
>> > from the CPU or called directly if we return from the ioctl to
>> > userspace.
>> >
>> > One caveat is that we have to save and restore the timer state in both
>> > kvm_timer_vcpu_[put/load] and kvm_timer_[schedule/unschedule], because
>> > we can have the following flows:
>> >
>> >   1. kvm_vcpu_block
>> >   2. kvm_timer_schedule
>> >   3. schedule
>> >   4. kvm_timer_vcpu_put (preempt notifier)
>> >   5. schedule (vcpu thread gets scheduled back)
>> >   6. kvm_timer_vcpu_load (preempt notifier)
>> >   7. kvm_timer_unschedule
>> >
>> > And a version where we don't actually call schedule:
>> >
>> >   1. kvm_vcpu_block
>> >   2. kvm_timer_schedule
>> >   7. kvm_timer_unschedule
>> >
>> > Since kvm_timer_[schedule/unschedule] may not be followed by put/load,
>> > but put/load also may be called independently, we call the timer
>> > save/restore functions from both paths.  Since they rely on the loaded
>> > flag to never save/restore when unnecessary, this doesn't cause any
>> > harm, and we ensure that all invokations of either set of functions work
>> > as intended.
>> >
>> > An added benefit beyond not having to read and write the timer sysregs
>> > on every entry and exit is that we no longer have to actively write the
>> > active state to the physical distributor, because we configured the
>> > irq for the vtimer to only get a priority drop when handling the
>> > interrupt in the GIC driver (we called irq_set_vcpu_affinity()), and
>> > the interrupt stays active after firing on the host.
>> >
>> > Signed-off-by: Christoffer Dall <cd...@linaro.org>
>> > ---
>> >
>> > Notes:
>> > Changes since v3:
>> >  - Added comments explaining the 'loaded' flag and made other 
>> > clarifying
>> >comments.
>> >  - No longer rely on the armed flag to conditionally save/restore 
>> > state,
>> >as we already rely on the 'loaded' flag to not repetitively
>> >save/restore state.
>> >  - Reworded parts of the commit message.
>> >  - Removed renames not belonging to this patch.
>> >  - Added warning in kvm_arch_timer_handler in case we see spurious
>> >interrupts, for example if the hardware doesn't retire the
>> >level-triggered timer signal fast enough.
>> >
>> >  include/kvm/arm_arch_timer.h |  16 ++-
>> >  virt/kvm/arm/arch_timer.c| 237 
>> > +++
>> >  virt/kvm/arm/arm.c   |  19 +++-
>> >  3 files changed, 178 insertions(+), 94 deletions(-)
>> >
>> > diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
>&g

Re: [PATCH v4 14/20] KVM: arm/arm64: Avoid timer save/restore in vcpu entry/exit

2017-11-16 Thread Jintack Lim
On Thu, Nov 16, 2017 at 3:30 PM, Jintack Lim <jint...@cs.columbia.edu> wrote:
> Hi Christoffer,
>
> On Fri, Oct 20, 2017 at 7:49 AM, Christoffer Dall
> <christoffer.d...@linaro.org> wrote:
>> From: Christoffer Dall <cd...@linaro.org>
>>
>> We don't need to save and restore the hardware timer state and examine
>> if it generates interrupts on on every entry/exit to the guest.  The
>> timer hardware is perfectly capable of telling us when it has expired
>> by signaling interrupts.
>>
>> When taking a vtimer interrupt in the host, we don't want to mess with
>> the timer configuration, we just want to forward the physical interrupt
>> to the guest as a virtual interrupt.  We can use the split priority drop
>> and deactivate feature of the GIC to do this, which leaves an EOI'ed
>> interrupt active on the physical distributor, making sure we don't keep
>> taking timer interrupts which would prevent the guest from running.  We
>> can then forward the physical interrupt to the VM using the HW bit in
>> the LR of the GIC, like we do already, which lets the guest directly
>> deactivate both the physical and virtual timer simultaneously, allowing
>> the timer hardware to exit the VM and generate a new physical interrupt
>> when the timer output is again asserted later on.
>>
>> We do need to capture this state when migrating VCPUs between physical
>> CPUs, however, which we use the vcpu put/load functions for, which are
>> called through preempt notifiers whenever the thread is scheduled away
>> from the CPU or called directly if we return from the ioctl to
>> userspace.
>>
>> One caveat is that we have to save and restore the timer state in both
>> kvm_timer_vcpu_[put/load] and kvm_timer_[schedule/unschedule], because
>> we can have the following flows:
>>
>>   1. kvm_vcpu_block
>>   2. kvm_timer_schedule
>>   3. schedule
>>   4. kvm_timer_vcpu_put (preempt notifier)
>>   5. schedule (vcpu thread gets scheduled back)
>>   6. kvm_timer_vcpu_load (preempt notifier)
>>   7. kvm_timer_unschedule
>>
>> And a version where we don't actually call schedule:
>>
>>   1. kvm_vcpu_block
>>   2. kvm_timer_schedule
>>   7. kvm_timer_unschedule
>>
>> Since kvm_timer_[schedule/unschedule] may not be followed by put/load,
>> but put/load also may be called independently, we call the timer
>> save/restore functions from both paths.  Since they rely on the loaded
>> flag to never save/restore when unnecessary, this doesn't cause any
>> harm, and we ensure that all invokations of either set of functions work
>> as intended.
>>
>> An added benefit beyond not having to read and write the timer sysregs
>> on every entry and exit is that we no longer have to actively write the
>> active state to the physical distributor, because we configured the
>> irq for the vtimer to only get a priority drop when handling the
>> interrupt in the GIC driver (we called irq_set_vcpu_affinity()), and
>> the interrupt stays active after firing on the host.
>>
>> Signed-off-by: Christoffer Dall <cd...@linaro.org>
>> ---
>>
>> Notes:
>> Changes since v3:
>>  - Added comments explaining the 'loaded' flag and made other clarifying
>>comments.
>>  - No longer rely on the armed flag to conditionally save/restore state,
>>as we already rely on the 'loaded' flag to not repetitively
>>save/restore state.
>>  - Reworded parts of the commit message.
>>  - Removed renames not belonging to this patch.
>>  - Added warning in kvm_arch_timer_handler in case we see spurious
>>interrupts, for example if the hardware doesn't retire the
>>level-triggered timer signal fast enough.
>>
>>  include/kvm/arm_arch_timer.h |  16 ++-
>>  virt/kvm/arm/arch_timer.c| 237 
>> +++
>>  virt/kvm/arm/arm.c   |  19 +++-
>>  3 files changed, 178 insertions(+), 94 deletions(-)
>>
>> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
>> index 184c3ef2df93..c538f707e1c1 100644
>> --- a/include/kvm/arm_arch_timer.h
>> +++ b/include/kvm/arm_arch_timer.h
>> @@ -31,8 +31,15 @@ struct arch_timer_context {
>> /* Timer IRQ */
>> struct kvm_irq_levelirq;
>>
>> -   /* Active IRQ state caching */
>> -   boolactive_cleared_last;
>> +   /*
>> +* We have multiple paths which can save/restore the timer state
>> +  

Re: [PATCH v4 14/20] KVM: arm/arm64: Avoid timer save/restore in vcpu entry/exit

2017-11-16 Thread Jintack Lim
Hi Christoffer,

On Fri, Oct 20, 2017 at 7:49 AM, Christoffer Dall
 wrote:
> From: Christoffer Dall 
>
> We don't need to save and restore the hardware timer state and examine
> if it generates interrupts on on every entry/exit to the guest.  The
> timer hardware is perfectly capable of telling us when it has expired
> by signaling interrupts.
>
> When taking a vtimer interrupt in the host, we don't want to mess with
> the timer configuration, we just want to forward the physical interrupt
> to the guest as a virtual interrupt.  We can use the split priority drop
> and deactivate feature of the GIC to do this, which leaves an EOI'ed
> interrupt active on the physical distributor, making sure we don't keep
> taking timer interrupts which would prevent the guest from running.  We
> can then forward the physical interrupt to the VM using the HW bit in
> the LR of the GIC, like we do already, which lets the guest directly
> deactivate both the physical and virtual timer simultaneously, allowing
> the timer hardware to exit the VM and generate a new physical interrupt
> when the timer output is again asserted later on.
>
> We do need to capture this state when migrating VCPUs between physical
> CPUs, however, which we use the vcpu put/load functions for, which are
> called through preempt notifiers whenever the thread is scheduled away
> from the CPU or called directly if we return from the ioctl to
> userspace.
>
> One caveat is that we have to save and restore the timer state in both
> kvm_timer_vcpu_[put/load] and kvm_timer_[schedule/unschedule], because
> we can have the following flows:
>
>   1. kvm_vcpu_block
>   2. kvm_timer_schedule
>   3. schedule
>   4. kvm_timer_vcpu_put (preempt notifier)
>   5. schedule (vcpu thread gets scheduled back)
>   6. kvm_timer_vcpu_load (preempt notifier)
>   7. kvm_timer_unschedule
>
> And a version where we don't actually call schedule:
>
>   1. kvm_vcpu_block
>   2. kvm_timer_schedule
>   7. kvm_timer_unschedule
>
> Since kvm_timer_[schedule/unschedule] may not be followed by put/load,
> but put/load also may be called independently, we call the timer
> save/restore functions from both paths.  Since they rely on the loaded
> flag to never save/restore when unnecessary, this doesn't cause any
> harm, and we ensure that all invokations of either set of functions work
> as intended.
>
> An added benefit beyond not having to read and write the timer sysregs
> on every entry and exit is that we no longer have to actively write the
> active state to the physical distributor, because we configured the
> irq for the vtimer to only get a priority drop when handling the
> interrupt in the GIC driver (we called irq_set_vcpu_affinity()), and
> the interrupt stays active after firing on the host.
>
> Signed-off-by: Christoffer Dall 
> ---
>
> Notes:
> Changes since v3:
>  - Added comments explaining the 'loaded' flag and made other clarifying
>comments.
>  - No longer rely on the armed flag to conditionally save/restore state,
>as we already rely on the 'loaded' flag to not repetitively
>save/restore state.
>  - Reworded parts of the commit message.
>  - Removed renames not belonging to this patch.
>  - Added warning in kvm_arch_timer_handler in case we see spurious
>interrupts, for example if the hardware doesn't retire the
>level-triggered timer signal fast enough.
>
>  include/kvm/arm_arch_timer.h |  16 ++-
>  virt/kvm/arm/arch_timer.c| 237 
> +++
>  virt/kvm/arm/arm.c   |  19 +++-
>  3 files changed, 178 insertions(+), 94 deletions(-)
>
> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> index 184c3ef2df93..c538f707e1c1 100644
> --- a/include/kvm/arm_arch_timer.h
> +++ b/include/kvm/arm_arch_timer.h
> @@ -31,8 +31,15 @@ struct arch_timer_context {
> /* Timer IRQ */
> struct kvm_irq_levelirq;
>
> -   /* Active IRQ state caching */
> -   boolactive_cleared_last;
> +   /*
> +* We have multiple paths which can save/restore the timer state
> +* onto the hardware, so we need some way of keeping track of
> +* where the latest state is.
> +*
> +* loaded == true:  State is loaded on the hardware registers.
> +* loaded == false: State is stored in memory.
> +*/
> +   boolloaded;
>
> /* Virtual offset */
> u64 cntvoff;
> @@ -78,10 +85,15 @@ void kvm_timer_unschedule(struct kvm_vcpu *vcpu);
>
>  u64 kvm_phys_timer_read(void);
>
> +void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu);
>  void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
>
>  void kvm_timer_init_vhe(void);
>
>  #define vcpu_vtimer(v) (&(v)->arch.timer_cpu.vtimer)
>  #define vcpu_ptimer(v) (&(v)->arch.timer_cpu.ptimer)
> +
> +void 

[RFC PATCH v2 29/31] KVM: arm64: Respect the virtual HCR_EL2.AT and NV setting

2017-10-02 Thread Jintack Lim
Forward system instruction traps to the virtual EL2 if a corresponding
bit in the virtual HCR_EL2 is set.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---

Notes:
v1-->v2:
This is a new commit.  We can rework existing forward_nv_traps() and
forward_nv1_traps() defined in rfc-v2 cpu patches to reuse forward_traps()
function

 arch/arm64/include/asm/kvm_arm.h |  1 +
 arch/arm64/kvm/sys_regs.c| 69 +---
 2 files changed, 44 insertions(+), 26 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index e160895..925edfd 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -23,6 +23,7 @@
 #include 
 
 /* Hyp Configuration Register (HCR) bits */
+#define HCR_AT (UL(1) << 44)
 #define HCR_NV1(UL(1) << 43)
 #define HCR_NV (UL(1) << 42)
 #define HCR_E2H(UL(1) << 34)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index eb91f00..89e73af 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -966,6 +966,23 @@ static bool access_cntp_cval(struct kvm_vcpu *vcpu,
return true;
 }
 
+static bool forward_traps(struct kvm_vcpu *vcpu, u64 control_bit)
+{
+   bool control_bit_set;
+
+   control_bit_set = vcpu_sys_reg(vcpu, HCR_EL2) & control_bit;
+   if (!vcpu_mode_el2(vcpu) && control_bit_set) {
+   kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+   return true;
+   }
+   return false;
+}
+
+static bool forward_at_traps(struct kvm_vcpu *vcpu)
+{
+   return forward_traps(vcpu, HCR_AT);
+}
+
 /* This function is to support the recursive nested virtualization */
 bool forward_nv_traps(struct kvm_vcpu *vcpu)
 {
@@ -1948,32 +1965,32 @@ static bool handle_ipas2e1is(struct kvm_vcpu *vcpu, 
struct sys_reg_params *p,
 #define SYS_INSN_TO_DESC(insn, access_fn, forward_fn)  \
{ SYS_DESC((insn)), (access_fn), NULL, 0, 0, NULL, NULL, (forward_fn) }
 static struct sys_reg_desc sys_insn_descs[] = {
-   SYS_INSN_TO_DESC(AT_S1E1R, handle_s1e01, NULL),
-   SYS_INSN_TO_DESC(AT_S1E1W, handle_s1e01, NULL),
-   SYS_INSN_TO_DESC(AT_S1E0R, handle_s1e01, NULL),
-   SYS_INSN_TO_DESC(AT_S1E0W, handle_s1e01, NULL),
-   SYS_INSN_TO_DESC(AT_S1E1RP, handle_s1e01, NULL),
-   SYS_INSN_TO_DESC(AT_S1E1WP, handle_s1e01, NULL),
-   SYS_INSN_TO_DESC(AT_S1E2R, handle_s1e2, NULL),
-   SYS_INSN_TO_DESC(AT_S1E2W, handle_s1e2, NULL),
-   SYS_INSN_TO_DESC(AT_S12E1R, handle_s12r, NULL),
-   SYS_INSN_TO_DESC(AT_S12E1W, handle_s12w, NULL),
-   SYS_INSN_TO_DESC(AT_S12E0R, handle_s12r, NULL),
-   SYS_INSN_TO_DESC(AT_S12E0W, handle_s12w, NULL),
-   SYS_INSN_TO_DESC(TLBI_IPAS2E1IS, handle_ipas2e1is, NULL),
-   SYS_INSN_TO_DESC(TLBI_IPAS2LE1IS, handle_ipas2e1is, NULL),
-   SYS_INSN_TO_DESC(TLBI_ALLE2IS, handle_alle2is, NULL),
-   SYS_INSN_TO_DESC(TLBI_VAE2IS, handle_vae2, NULL),
-   SYS_INSN_TO_DESC(TLBI_ALLE1IS, handle_alle1is, NULL),
-   SYS_INSN_TO_DESC(TLBI_VALE2IS, handle_vae2, NULL),
-   SYS_INSN_TO_DESC(TLBI_VMALLS12E1IS, handle_vmalls12e1is, NULL),
-   SYS_INSN_TO_DESC(TLBI_IPAS2E1, handle_ipas2e1is, NULL),
-   SYS_INSN_TO_DESC(TLBI_IPAS2LE1, handle_ipas2e1is, NULL),
-   SYS_INSN_TO_DESC(TLBI_ALLE2, handle_alle2, NULL),
-   SYS_INSN_TO_DESC(TLBI_VAE2, handle_vae2, NULL),
-   SYS_INSN_TO_DESC(TLBI_ALLE1, handle_alle1is, NULL),
-   SYS_INSN_TO_DESC(TLBI_VALE2, handle_vae2, NULL),
-   SYS_INSN_TO_DESC(TLBI_VMALLS12E1, handle_vmalls12e1is, NULL),
+   SYS_INSN_TO_DESC(AT_S1E1R, handle_s1e01, forward_at_traps),
+   SYS_INSN_TO_DESC(AT_S1E1W, handle_s1e01, forward_at_traps),
+   SYS_INSN_TO_DESC(AT_S1E0R, handle_s1e01, forward_at_traps),
+   SYS_INSN_TO_DESC(AT_S1E0W, handle_s1e01, forward_at_traps),
+   SYS_INSN_TO_DESC(AT_S1E1RP, handle_s1e01, forward_at_traps),
+   SYS_INSN_TO_DESC(AT_S1E1WP, handle_s1e01, forward_at_traps),
+   SYS_INSN_TO_DESC(AT_S1E2R, handle_s1e2, forward_nv_traps),
+   SYS_INSN_TO_DESC(AT_S1E2W, handle_s1e2, forward_nv_traps),
+   SYS_INSN_TO_DESC(AT_S12E1R, handle_s12r, forward_nv_traps),
+   SYS_INSN_TO_DESC(AT_S12E1W, handle_s12w, forward_nv_traps),
+   SYS_INSN_TO_DESC(AT_S12E0R, handle_s12r, forward_nv_traps),
+   SYS_INSN_TO_DESC(AT_S12E0W, handle_s12w, forward_nv_traps),
+   SYS_INSN_TO_DESC(TLBI_IPAS2E1IS, handle_ipas2e1is, forward_nv_traps),
+   SYS_INSN_TO_DESC(TLBI_IPAS2LE1IS, handle_ipas2e1is, forward_nv_traps),
+   SYS_INSN_TO_DESC(TLBI_ALLE2IS, handle_alle2is, forward_nv_traps),
+   SYS_INSN_TO_DESC(TLBI_VAE2IS, handle_vae2, forward_nv_traps),
+   SYS_INSN_TO_DESC(TLBI_ALLE1IS, handle_alle1is, forward_nv_traps),
+   SYS_INSN_TO_DESC(TLBI_VALE2IS, handle_vae2, forward_nv_traps),
+   SYS_INSN_TO_DESC(TLBI_VMALLS1

[RFC PATCH v2 31/31] KVM: arm64: Fixes to toggle_cache for nesting

2017-10-02 Thread Jintack Lim
From: Christoffer Dall <christoffer.d...@linaro.org>

So far we were flushing almost the entire universe whenever a VM would
load/unload the SCTLR_EL1 and the two versions of that register had
different MMU enabled settings.  This turned out to be so slow that it
prevented forward progress for a nested VM, because a scheduler timer
tick interrupt would always be pending when we reached the nested VM.

To avoid this problem, we consider the SCTLR_EL2 when evaluating if
caches are on or off when entering virtual EL2 (because this is the
value that we end up shadowing onto the hardware EL1 register).

Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_mmu.h | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 601f431..7a1c581 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -240,7 +240,10 @@ static inline bool kvm_page_empty(void *ptr)
 
 static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
 {
-   return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
+   if (vcpu_mode_el2(vcpu))
+   return (vcpu_sys_reg(vcpu, SCTLR_EL2) & 0b101) == 0b101;
+   else
+   return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
 }
 
 static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu,
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 27/31] KVM: arm64: Emulate TLBI VMALLS12E1(IS) instruction

2017-10-02 Thread Jintack Lim
Based on the same principle as TLBI ALLE1(IS) emulation, we clear the
mappings in the shadow stage-2 page tables and invalidate TLB entries.
But this time we do it only for the current VMID from the guest
hypervisor's perspective, not for all VMIDs.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_mmu.h |  2 ++
 arch/arm64/kvm/mmu-nested.c  | 23 +++
 arch/arm64/kvm/sys_regs.c| 33 +++--
 3 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 239bb89..6681be1 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -345,6 +345,8 @@ int kvm_s2_handle_perm_fault(struct kvm_vcpu *vcpu, 
phys_addr_t fault_ipa,
 void kvm_nested_s2_clear(struct kvm *kvm);
 void kvm_nested_s2_flush(struct kvm *kvm);
 int kvm_inject_s2_fault(struct kvm_vcpu *vcpu, u64 esr_el2);
+bool kvm_nested_s2_clear_curr_vmid(struct kvm_vcpu *vcpu, phys_addr_t start,
+  u64 size);
 
 static inline u64 kvm_get_vttbr(struct kvm_s2_vmid *vmid,
struct kvm_s2_mmu *mmu)
diff --git a/arch/arm64/kvm/mmu-nested.c b/arch/arm64/kvm/mmu-nested.c
index a440d7b..2189f2b 100644
--- a/arch/arm64/kvm/mmu-nested.c
+++ b/arch/arm64/kvm/mmu-nested.c
@@ -349,6 +349,29 @@ static struct kvm_nested_s2_mmu *lookup_nested_mmu(struct 
kvm_vcpu *vcpu,
return NULL;
 }
 
+/*
+ * Clear mappings in the shadow stage 2 page tables for the current VMID from
+ * the perspective of the guest hypervisor.
+ * This function expects kvm->mmu_lock to be held.
+ */
+bool kvm_nested_s2_clear_curr_vmid(struct kvm_vcpu *vcpu, phys_addr_t start,
+  u64 size)
+{
+   struct kvm_nested_s2_mmu *nested_mmu;
+   u64 vttbr = vcpu_sys_reg(vcpu, VTTBR_EL2);
+
+   /*
+* Look up a mmu that is used for the current VMID from the guest
+* hypervisor's view.
+*/
+   nested_mmu = lookup_nested_mmu(vcpu, vttbr);
+   if (!nested_mmu)
+   return false;
+
+   kvm_unmap_stage2_range(vcpu->kvm, _mmu->mmu, start, size);
+   return true;
+}
+
 /**
  * create_nested_mmu - create mmu for the given virtual VMID
  *
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 5a82de9..5fd47ad 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1820,6 +1820,35 @@ static bool handle_alle1is(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
return true;
 }
 
+static bool handle_vmalls12e1is(struct kvm_vcpu *vcpu, struct sys_reg_params 
*p,
+   const struct sys_reg_desc *r)
+{
+   u64 vttbr;
+   struct kvm_s2_mmu *mmu;
+   bool ret;
+
+   spin_lock(>kvm->mmu_lock);
+   /*
+* Clear mappings in the shadow page tables and invalidate the stage
+* 1 and 2 TLB entries via kvm_tlb_flush_vmid_ipa() for the current
+* VMID.
+*/
+   ret = kvm_nested_s2_clear_curr_vmid(vcpu, 0, KVM_PHYS_SIZE);
+   spin_unlock(>kvm->mmu_lock);
+
+   if (!ret) {
+   /*
+* Invalidate TLB entries explicitly for the case that the
+* current VMID is for the host OS in the VM; we don't manage
+* shadow stage 2 page tables for it.
+*/
+   mmu = >kvm->arch.mmu;
+   vttbr = kvm_get_vttbr(>vmid, mmu);
+   kvm_call_hyp(__kvm_tlb_flush_vmid, vttbr);
+   }
+   return true;
+}
+
 /*
  * AT instruction emulation
  *
@@ -1907,14 +1936,14 @@ static bool handle_alle1is(struct kvm_vcpu *vcpu, 
struct sys_reg_params *p,
SYS_INSN_TO_DESC(TLBI_VAE2IS, handle_vae2, NULL),
SYS_INSN_TO_DESC(TLBI_ALLE1IS, handle_alle1is, NULL),
SYS_INSN_TO_DESC(TLBI_VALE2IS, handle_vae2, NULL),
-   SYS_INSN_TO_DESC(TLBI_VMALLS12E1IS, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_VMALLS12E1IS, handle_vmalls12e1is, NULL),
SYS_INSN_TO_DESC(TLBI_IPAS2E1, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_IPAS2LE1, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_ALLE2, handle_alle2, NULL),
SYS_INSN_TO_DESC(TLBI_VAE2, handle_vae2, NULL),
SYS_INSN_TO_DESC(TLBI_ALLE1, handle_alle1is, NULL),
SYS_INSN_TO_DESC(TLBI_VALE2, handle_vae2, NULL),
-   SYS_INSN_TO_DESC(TLBI_VMALLS12E1, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_VMALLS12E1, handle_vmalls12e1is, NULL),
 };
 
 #define reg_to_match_value(x)  \
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 14/31] KVM: arm/arm64: Forward the guest hypervisor's stage 2 permission faults

2017-10-02 Thread Jintack Lim
From: Christoffer Dall <christoffer.d...@linaro.org>

We can have discrepancies between the nested stage 2 page table and the
shadow one in a couple of cases.  For example, the guest hypervisor can
mark a page writable but the host hypervisor maps the page read-only in
the shadow page table, if using something like KSM on the host level.
In this case, a write fault is handled directly by the host hypervisor.
But we could also simply have a read-only page mapped read-only in both
tables, in which case the host hypervisor cannot do anything else than
telling the guest hypervisor about the fault.

Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm/include/asm/kvm_mmu.h   |  7 +++
 arch/arm64/include/asm/kvm_mmu.h |  2 ++
 arch/arm64/kvm/mmu-nested.c  | 22 ++
 virt/kvm/arm/mmu.c   |  7 +++
 4 files changed, 38 insertions(+)

diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 6a22846..1c5b652 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -237,6 +237,13 @@ static inline int kvm_walk_nested_s2(struct kvm_vcpu 
*vcpu, phys_addr_t gipa,
return 0;
 }
 
+static inline int kvm_s2_handle_perm_fault(struct kvm_vcpu *vcpu,
+  phys_addr_t fault_ipa,
+  struct kvm_s2_trans *trans)
+{
+   return 0;
+}
+
 static inline void kvm_nested_s2_unmap(struct kvm_vcpu *vcpu) { }
 static inline void kvm_nested_s2_free(struct kvm *kvm) { }
 static inline void kvm_nested_s2_wp(struct kvm *kvm) { }
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 425e4a2..239bb89 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -337,6 +337,8 @@ struct kvm_s2_trans {
 void update_nested_s2_mmu(struct kvm_vcpu *vcpu);
 int kvm_walk_nested_s2(struct kvm_vcpu *vcpu, phys_addr_t gipa,
   struct kvm_s2_trans *result);
+int kvm_s2_handle_perm_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+struct kvm_s2_trans *trans);
 void kvm_nested_s2_unmap(struct kvm_vcpu *vcpu);
 void kvm_nested_s2_free(struct kvm *kvm);
 void kvm_nested_s2_wp(struct kvm *kvm);
diff --git a/arch/arm64/kvm/mmu-nested.c b/arch/arm64/kvm/mmu-nested.c
index 75570cc..a440d7b 100644
--- a/arch/arm64/kvm/mmu-nested.c
+++ b/arch/arm64/kvm/mmu-nested.c
@@ -271,6 +271,28 @@ int kvm_walk_nested_s2(struct kvm_vcpu *vcpu, phys_addr_t 
gipa,
return walk_nested_s2_pgd(vcpu, gipa, , result);
 }
 
+/*
+ * Returns non-zero if permission fault is handled by injecting it to the next
+ * level hypervisor.
+ */
+int kvm_s2_handle_perm_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
+struct kvm_s2_trans *trans)
+{
+   unsigned long fault_status = kvm_vcpu_trap_get_fault_type(vcpu);
+   bool write_fault = kvm_is_write_fault(vcpu);
+
+   if (fault_status != FSC_PERM)
+   return 0;
+
+   if ((write_fault && !trans->writable) ||
+   (!write_fault && !trans->readable)) {
+   trans->esr = esr_s2_fault(vcpu, trans->level, ESR_ELx_FSC_PERM);
+   return 1;
+   }
+
+   return 0;
+}
+
 /* expects kvm->mmu_lock to be held */
 void kvm_nested_s2_wp(struct kvm *kvm)
 {
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index 74941ad..4fb7b3b 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -1591,6 +1591,13 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct 
kvm_run *run)
if (ret)
goto out_unlock;
 
+   nested_trans.esr = 0;
+   ret = kvm_s2_handle_perm_fault(vcpu, fault_ipa, _trans);
+   if (nested_trans.esr)
+   kvm_inject_s2_fault(vcpu, nested_trans.esr);
+   if (ret)
+   goto out_unlock;
+
ipa = nested_trans.output;
}
 
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 21/31] KVM: arm64: Emulate AT S1E[01] instructions

2017-10-02 Thread Jintack Lim
Emulate AT S1E[01] instructions by issuing the same instructions in EL2. We
set the physical EL1 registers, NV and NV1 bits as described in the AT
instruction emulation overview.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_emulate.h | 11 +++
 arch/arm64/kvm/sys_regs.c| 32 ++--
 2 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h 
b/arch/arm64/include/asm/kvm_emulate.h
index 4c47bc7..a494db2 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -185,6 +185,17 @@ static inline bool vcpu_el2_tge_is_set(const struct 
kvm_vcpu *vcpu)
return (vcpu_sys_reg(vcpu, HCR_EL2) & HCR_TGE);
 }
 
+
+/*
+ * When the NV and NV1 bits are set, the EL2 page table format is used for the
+ * EL1 translation regime.
+ */
+static inline bool vcpu_el2_format_used(const struct kvm_vcpu *vcpu)
+{
+   return ((vcpu_sys_reg(vcpu, HCR_EL2) & HCR_NV) &&
+   (vcpu_sys_reg(vcpu, HCR_EL2) & HCR_NV1));
+}
+
 static inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu)
 {
/*
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index d8728cc..a82274f 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1621,6 +1621,26 @@ static bool access_id_aa64mmfr0_el1(struct kvm_vcpu *v,
{ SYS_DESC(SYS_SP_EL2), NULL, reset_special, SP_EL2, 0},
 };
 
+static bool handle_s1e01(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+const struct sys_reg_desc *r)
+{
+   struct kvm_cpu_context *ctxt = >arch.ctxt;
+   bool el2_format;
+   int sys_encoding = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
+
+   /* See '2. EL0/EL1 AT instructions: S1E[01]x, S12E1x' table. */
+   if (vcpu_el2_e2h_is_set(vcpu) && vcpu_el2_tge_is_set(vcpu))
+   ctxt->hw_sys_regs = ctxt->shadow_sys_regs;
+   else
+   ctxt->hw_sys_regs = ctxt->sys_regs;
+
+   el2_format = vcpu_el2_format_used(vcpu);
+
+   kvm_call_hyp(__kvm_at_insn, vcpu, p->regval, el2_format, sys_encoding);
+
+   return true;
+}
+
 /*
  * AT instruction emulation
  *
@@ -1690,12 +1710,12 @@ static bool access_id_aa64mmfr0_el1(struct kvm_vcpu *v,
 #define SYS_INSN_TO_DESC(insn, access_fn, forward_fn)  \
{ SYS_DESC((insn)), (access_fn), NULL, 0, 0, NULL, NULL, (forward_fn) }
 static struct sys_reg_desc sys_insn_descs[] = {
-   SYS_INSN_TO_DESC(AT_S1E1R, NULL, NULL),
-   SYS_INSN_TO_DESC(AT_S1E1W, NULL, NULL),
-   SYS_INSN_TO_DESC(AT_S1E0R, NULL, NULL),
-   SYS_INSN_TO_DESC(AT_S1E0W, NULL, NULL),
-   SYS_INSN_TO_DESC(AT_S1E1RP, NULL, NULL),
-   SYS_INSN_TO_DESC(AT_S1E1WP, NULL, NULL),
+   SYS_INSN_TO_DESC(AT_S1E1R, handle_s1e01, NULL),
+   SYS_INSN_TO_DESC(AT_S1E1W, handle_s1e01, NULL),
+   SYS_INSN_TO_DESC(AT_S1E0R, handle_s1e01, NULL),
+   SYS_INSN_TO_DESC(AT_S1E0W, handle_s1e01, NULL),
+   SYS_INSN_TO_DESC(AT_S1E1RP, handle_s1e01, NULL),
+   SYS_INSN_TO_DESC(AT_S1E1WP, handle_s1e01, NULL),
SYS_INSN_TO_DESC(AT_S1E2R, NULL, NULL),
SYS_INSN_TO_DESC(AT_S1E2W, NULL, NULL),
SYS_INSN_TO_DESC(AT_S12E1R, NULL, NULL),
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 30/31] KVM: arm64: Emulate TLBI instructions accesible from EL1

2017-10-02 Thread Jintack Lim
Even though a guest hypervisor can execute TLBI instructions that are
accesible at EL1 without trap, it's wrong; All those TLBI instructions
work based on current VMID, and when running a guest hypervisor current
VMID is the one for itself, not the one from the virtual vttbr_el2. So
letting a guest hypervisor execute those TLBI instructions results in
invalidating its own TLB entries and leaving invalid TLB entries
unhandled.

Therefore we trap and emulate those TLBI instructions. The emulation is
simple; we find a shadow VMID mapped to the virtual vttbr_el2, set it in
the physical vttbr_el2, then execute the same instruction in EL2.

We don't set HCR_EL2.TTLB bit yet.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_asm.h |  1 +
 arch/arm64/include/asm/kvm_mmu.h |  1 +
 arch/arm64/include/asm/sysreg.h  | 15 
 arch/arm64/kvm/hyp/tlb.c | 52 
 arch/arm64/kvm/mmu-nested.c  |  3 +--
 arch/arm64/kvm/sys_regs.c| 50 ++
 6 files changed, 120 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index cd7fb85..ce331d7 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -56,6 +56,7 @@
 extern void __kvm_tlb_flush_vmid(u64 vttbr);
 extern void __kvm_tlb_flush_local_vmid(u64 vttbr);
 extern void __kvm_tlb_vae2(u64 vttbr, u64 va, u64 sys_encoding);
+extern void __kvm_tlb_el1_instr(u64 vttbr, u64 val, u64 sys_encoding);
 
 extern void __kvm_at_insn(struct kvm_vcpu *vcpu, unsigned long vaddr,
  bool el2_regime, int sys_encoding);
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 6681be1..601f431 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -347,6 +347,7 @@ int kvm_s2_handle_perm_fault(struct kvm_vcpu *vcpu, 
phys_addr_t fault_ipa,
 int kvm_inject_s2_fault(struct kvm_vcpu *vcpu, u64 esr_el2);
 bool kvm_nested_s2_clear_curr_vmid(struct kvm_vcpu *vcpu, phys_addr_t start,
   u64 size);
+struct kvm_nested_s2_mmu *lookup_nested_mmu(struct kvm_vcpu *vcpu, u64 vttbr);
 
 static inline u64 kvm_get_vttbr(struct kvm_s2_vmid *vmid,
struct kvm_s2_mmu *mmu)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 53df733..fd6b98a 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -386,10 +386,25 @@
 
 /* TLBI instructions */
 #define TLBI_Op0   1
+#define TLBI_Op1_EL1   0   /* Accessible from EL1 or higher */
 #define TLBI_Op1_EL2   4   /* Accessible from EL2 or higher */
 #define TLBI_CRn   8
+#define tlbi_insn_el1(CRm, Op2)sys_insn(TLBI_Op0, TLBI_Op1_EL1, 
TLBI_CRn, (CRm), (Op2))
 #define tlbi_insn_el2(CRm, Op2)sys_insn(TLBI_Op0, TLBI_Op1_EL2, 
TLBI_CRn, (CRm), (Op2))
 
+#define TLBI_VMALLE1IS tlbi_insn_el1(3, 0)
+#define TLBI_VAE1IStlbi_insn_el1(3, 1)
+#define TLBI_ASIDE1IS  tlbi_insn_el1(3, 2)
+#define TLBI_VAAE1IS   tlbi_insn_el1(3, 3)
+#define TLBI_VALE1IS   tlbi_insn_el1(3, 5)
+#define TLBI_VAALE1IS  tlbi_insn_el1(3, 7)
+#define TLBI_VMALLE1   tlbi_insn_el1(7, 0)
+#define TLBI_VAE1  tlbi_insn_el1(7, 1)
+#define TLBI_ASIDE1tlbi_insn_el1(7, 2)
+#define TLBI_VAAE1 tlbi_insn_el1(7, 3)
+#define TLBI_VALE1 tlbi_insn_el1(7, 5)
+#define TLBI_VAALE1tlbi_insn_el1(7, 7)
+
 #define TLBI_IPAS2E1IS tlbi_insn_el2(0, 1)
 #define TLBI_IPAS2LE1IStlbi_insn_el2(0, 5)
 #define TLBI_ALLE2IS   tlbi_insn_el2(3, 0)
diff --git a/arch/arm64/kvm/hyp/tlb.c b/arch/arm64/kvm/hyp/tlb.c
index bd8b92c..096c234 100644
--- a/arch/arm64/kvm/hyp/tlb.c
+++ b/arch/arm64/kvm/hyp/tlb.c
@@ -179,3 +179,55 @@ void __hyp_text __kvm_tlb_vae2(u64 vttbr, u64 va, u64 
sys_encoding)
 
__tlb_switch_to_host()();
 }
+
+void __hyp_text __kvm_tlb_el1_instr(u64 vttbr, u64 val, u64 sys_encoding)
+{
+   /* Switch to requested VMID */
+   __tlb_switch_to_guest()(vttbr);
+
+   /* Execute the same instruction as the guest hypervisor did */
+   switch (sys_encoding) {
+   case TLBI_VMALLE1IS:
+   __tlbi(vmalle1is);
+   break;
+   case TLBI_VAE1IS:
+   __tlbi(vae1is, val);
+   break;
+   case TLBI_ASIDE1IS:
+   __tlbi(aside1is, val);
+   break;
+   case TLBI_VAAE1IS:
+   __tlbi(vaae1is, val);
+   break;
+   case TLBI_VALE1IS:
+   __tlbi(vale1is, val);
+   break;
+   case TLBI_VAALE1IS:
+   __tlbi(vaale1is, val);
+   break;
+   case TLBI_VMALLE1:
+   __tlbi(vmalle1);
+   break;
+   case TLBI_VAE1:
+   __tlbi(vae1, val);
+   break;
+   case TLBI_ASIDE1:
+   __tlbi(aside1, val);
+  

[RFC PATCH v2 26/31] KVM: arm64: Emulate TLBI ALLE1(IS)

2017-10-02 Thread Jintack Lim
TLBI ALLE1(IS) instruction invalidates all EL1&0 regime stage 1 and 2
TLB entries (on all PEs in the same Inner Shareable domain). To emulate
these instructions, we first need to clear all the mappings in the
shadow page tables since executing those instructions implies the change
of mappings in the stage 2 page tables maintained by the guest
hypervisor.  We then need to invalidate all EL1&0 regime stage 1 and 2
TLB entries of all VMIDs, which are assigned by the host hypervisor, for
this VM.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 29 +++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index a1ae8fb..5a82de9 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1795,6 +1795,31 @@ static bool handle_vae2(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
return true;
 }
 
+static bool handle_alle1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+  const struct sys_reg_desc *r)
+{
+   struct kvm_s2_mmu *mmu = >kvm->arch.mmu;
+   u64 vttbr = kvm_get_vttbr(>vmid, mmu);
+
+   if (vcpu->kvm->arch.mmu.vmid.vmid_gen) {
+   /*
+* Invalidate the stage 1 and 2 TLB entries for the host OS
+* in a VM only if there is one.
+*/
+   kvm_call_hyp(__kvm_tlb_flush_vmid, vttbr);
+   }
+
+   spin_lock(>kvm->mmu_lock);
+   /*
+* Clear all mappings in the shadow page tables and invalidate the stage
+* 1 and 2 TLB entries via kvm_tlb_flush_vmid_ipa().
+*/
+   kvm_nested_s2_clear(vcpu->kvm);
+   spin_unlock(>kvm->mmu_lock);
+
+   return true;
+}
+
 /*
  * AT instruction emulation
  *
@@ -1880,14 +1905,14 @@ static bool handle_vae2(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
SYS_INSN_TO_DESC(TLBI_IPAS2LE1IS, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_ALLE2IS, handle_alle2is, NULL),
SYS_INSN_TO_DESC(TLBI_VAE2IS, handle_vae2, NULL),
-   SYS_INSN_TO_DESC(TLBI_ALLE1IS, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_ALLE1IS, handle_alle1is, NULL),
SYS_INSN_TO_DESC(TLBI_VALE2IS, handle_vae2, NULL),
SYS_INSN_TO_DESC(TLBI_VMALLS12E1IS, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_IPAS2E1, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_IPAS2LE1, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_ALLE2, handle_alle2, NULL),
SYS_INSN_TO_DESC(TLBI_VAE2, handle_vae2, NULL),
-   SYS_INSN_TO_DESC(TLBI_ALLE1, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_ALLE1, handle_alle1is, NULL),
SYS_INSN_TO_DESC(TLBI_VALE2, handle_vae2, NULL),
SYS_INSN_TO_DESC(TLBI_VMALLS12E1, NULL, NULL),
 };
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 24/31] KVM: arm64: Emulate TLBI ALLE2(IS) instruction

2017-10-02 Thread Jintack Lim
Emulate TLBI ALLE2(IS) instruction executed in the virtual EL2. Since we
emulate the virtual EL2 in the EL1, we invalidate EL1&0 regime stage 1
TLB entries with setting vttbr_el2 having the VMID of the virtual EL2.

Note that we are able to emulate TLBI ALLE2IS precisely by only
invalidating stage 1 TLB entries via TLBI VMALL1IS instruction, but to
make it simeple, we reuse the existing function, __kvm_tlb_flush_vmid(),
which invalidates both of stage 1 and 2 TLB entries.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 35 +--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 7950ee0..90329b7 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1747,6 +1747,37 @@ static bool handle_s12w(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
return handle_s12(vcpu, p, r, true);
 }
 
+static bool handle_alle2(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+const struct sys_reg_desc *r)
+{
+   struct kvm_s2_mmu *mmu = >kvm->arch.mmu;
+   u64 vttbr = kvm_get_vttbr(>el2_vmid, mmu);
+
+   /*
+* To emulate invalidating all EL2 regime stage 1 TLB entries,
+* invalidate EL1&0 regime stage 1 TLB entries with the virtual EL2's
+* VMID.
+*/
+   kvm_call_hyp(__kvm_tlb_flush_local_vmid, vttbr);
+   return true;
+}
+
+static bool handle_alle2is(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+  const struct sys_reg_desc *r)
+{
+   struct kvm_s2_mmu *mmu = >kvm->arch.mmu;
+   u64 vttbr = kvm_get_vttbr(>el2_vmid, mmu);
+
+   /*
+* To emulate invalidating all EL2 regime stage 1 TLB entries for all
+* PEs, executing TLBI VMALLE1IS is enough. But reuse the existing
+* interface for the simplicity; invalidating stage 2 entries doesn't
+* affect the correctness.
+*/
+   kvm_call_hyp(__kvm_tlb_flush_vmid, vttbr);
+   return true;
+}
+
 /*
  * AT instruction emulation
  *
@@ -1830,14 +1861,14 @@ static bool handle_s12w(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
SYS_INSN_TO_DESC(AT_S12E0W, handle_s12w, NULL),
SYS_INSN_TO_DESC(TLBI_IPAS2E1IS, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_IPAS2LE1IS, NULL, NULL),
-   SYS_INSN_TO_DESC(TLBI_ALLE2IS, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_ALLE2IS, handle_alle2is, NULL),
SYS_INSN_TO_DESC(TLBI_VAE2IS, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_ALLE1IS, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_VALE2IS, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_VMALLS12E1IS, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_IPAS2E1, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_IPAS2LE1, NULL, NULL),
-   SYS_INSN_TO_DESC(TLBI_ALLE2, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_ALLE2, handle_alle2, NULL),
SYS_INSN_TO_DESC(TLBI_VAE2, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_ALLE1, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_VALE2, NULL, NULL),
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 16/31] KVM: arm64: Introduce sys_reg_desc.forward_trap

2017-10-02 Thread Jintack Lim
This introduces a function prototype to determine if we need to forward
system instruction traps to the virtual EL2. The implementation of
forward_trap functions for each system instruction will be added in
later patches.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 8 
 arch/arm64/kvm/sys_regs.h | 6 ++
 2 files changed, 14 insertions(+)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 541bb97..88ce172 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1661,6 +1661,14 @@ static void perform_access(struct kvm_vcpu *vcpu,
 */
BUG_ON(!r->access);
 
+   /*
+* Forward this trap to the virtual EL2 if the guest hypervisor has
+* configured to trap the current instruction.
+*/
+   if (nested_virt_in_use(vcpu) && r->forward_trap
+   && unlikely(r->forward_trap(vcpu)))
+   return;
+
/* Skip instruction if instructed so */
if (likely(r->access(vcpu, params, r)))
kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
index 827717b..6dd4008 100644
--- a/arch/arm64/kvm/sys_regs.h
+++ b/arch/arm64/kvm/sys_regs.h
@@ -61,6 +61,12 @@ struct sys_reg_desc {
const struct kvm_one_reg *reg, void __user *uaddr);
int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
const struct kvm_one_reg *reg, void __user *uaddr);
+
+   /*
+* Forward the trap to the virtual EL2 if the guest hypervisor has
+* configured to trap the current instruction.
+*/
+   bool (*forward_trap)(struct kvm_vcpu *vcpu);
 };
 
 static inline void print_sys_reg_instr(const struct sys_reg_params *p)
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 28/31] KVM: arm64: Emulate TLBI IPAS2E1* instructions

2017-10-02 Thread Jintack Lim
Based on the same principle as TLBI ALLE1(IS) and TLBI VMALLS12E1(IS)
emulation, we clear the mappings in the shadow stage-2 page tables and
invalidate TLB entries. We do it only for one mapping for the current
VMID from the guest hypervisor's view.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 38 ++
 1 file changed, 34 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 5fd47ad..eb91f00 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1849,6 +1849,36 @@ static bool handle_vmalls12e1is(struct kvm_vcpu *vcpu, 
struct sys_reg_params *p,
return true;
 }
 
+static bool handle_ipas2e1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+const struct sys_reg_desc *r)
+{
+   u64 vttbr;
+   struct kvm_s2_mmu *mmu;
+   bool ret;
+
+   spin_lock(>kvm->mmu_lock);
+   /*
+* Clear a mapping in the shadow page tables and invalidate the stage
+* 2 TLB entries via kvm_tlb_flush_vmid_ipa() for the current
+* VMID and the given ipa.
+*/
+   ret = kvm_nested_s2_clear_curr_vmid(vcpu, p->regval, PAGE_SIZE);
+   spin_unlock(>kvm->mmu_lock);
+
+   if (!ret) {
+   /*
+* Invalidate TLB entries explicitly for the case that the
+* current VMID is for the host OS in the VM; we don't manage
+* shadow stage 2 page tables for it.
+*/
+   mmu = >kvm->arch.mmu;
+   vttbr = kvm_get_vttbr(>vmid, mmu);
+   kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, vttbr, p->regval);
+   }
+
+   return true;
+}
+
 /*
  * AT instruction emulation
  *
@@ -1930,15 +1960,15 @@ static bool handle_vmalls12e1is(struct kvm_vcpu *vcpu, 
struct sys_reg_params *p,
SYS_INSN_TO_DESC(AT_S12E1W, handle_s12w, NULL),
SYS_INSN_TO_DESC(AT_S12E0R, handle_s12r, NULL),
SYS_INSN_TO_DESC(AT_S12E0W, handle_s12w, NULL),
-   SYS_INSN_TO_DESC(TLBI_IPAS2E1IS, NULL, NULL),
-   SYS_INSN_TO_DESC(TLBI_IPAS2LE1IS, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_IPAS2E1IS, handle_ipas2e1is, NULL),
+   SYS_INSN_TO_DESC(TLBI_IPAS2LE1IS, handle_ipas2e1is, NULL),
SYS_INSN_TO_DESC(TLBI_ALLE2IS, handle_alle2is, NULL),
SYS_INSN_TO_DESC(TLBI_VAE2IS, handle_vae2, NULL),
SYS_INSN_TO_DESC(TLBI_ALLE1IS, handle_alle1is, NULL),
SYS_INSN_TO_DESC(TLBI_VALE2IS, handle_vae2, NULL),
SYS_INSN_TO_DESC(TLBI_VMALLS12E1IS, handle_vmalls12e1is, NULL),
-   SYS_INSN_TO_DESC(TLBI_IPAS2E1, NULL, NULL),
-   SYS_INSN_TO_DESC(TLBI_IPAS2LE1, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_IPAS2E1, handle_ipas2e1is, NULL),
+   SYS_INSN_TO_DESC(TLBI_IPAS2LE1, handle_ipas2e1is, NULL),
SYS_INSN_TO_DESC(TLBI_ALLE2, handle_alle2, NULL),
SYS_INSN_TO_DESC(TLBI_VAE2, handle_vae2, NULL),
SYS_INSN_TO_DESC(TLBI_ALLE1, handle_alle1is, NULL),
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 15/31] KVM: arm64: Move system register helper functions around

2017-10-02 Thread Jintack Lim
From: Jintack Lim <jint...@cs.columbia.edu>

We are about to add a framework to handle system instruction traps. To
reuse existing helper functions, let's move them around.

No functional change.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 89 ---
 1 file changed, 45 insertions(+), 44 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 395b964..541bb97 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1621,6 +1621,51 @@ static bool access_id_aa64mmfr0_el1(struct kvm_vcpu *v,
{ SYS_DESC(SYS_SP_EL2), NULL, reset_special, SP_EL2, 0},
 };
 
+#define reg_to_match_value(x)  \
+   ({  \
+   unsigned long val;  \
+   val  = (x)->Op0 << 14;  \
+   val |= (x)->Op1 << 11;  \
+   val |= (x)->CRn << 7;   \
+   val |= (x)->CRm << 3;   \
+   val |= (x)->Op2;\
+   val;\
+})
+
+static int match_sys_reg(const void *key, const void *elt)
+{
+   const unsigned long pval = (unsigned long)key;
+   const struct sys_reg_desc *r = elt;
+
+   return pval - reg_to_match_value(r);
+}
+
+static const struct sys_reg_desc *find_reg(const struct sys_reg_params *params,
+const struct sys_reg_desc table[],
+unsigned int num)
+{
+   unsigned long pval = reg_to_match_value(params);
+
+   return bsearch((void *)pval, table, num, sizeof(table[0]),
+  match_sys_reg);
+}
+
+static void perform_access(struct kvm_vcpu *vcpu,
+  struct sys_reg_params *params,
+  const struct sys_reg_desc *r)
+{
+   /*
+* Not having an accessor means that we have configured a trap
+* that we don't know how to handle. This certainly qualifies
+* as a gross bug that should be fixed right away.
+*/
+   BUG_ON(!r->access);
+
+   /* Skip instruction if instructed so */
+   if (likely(r->access(vcpu, params, r)))
+   kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+}
+
 static bool trap_dbgidr(struct kvm_vcpu *vcpu,
struct sys_reg_params *p,
const struct sys_reg_desc *r)
@@ -1968,56 +2013,12 @@ static const struct sys_reg_desc 
*get_target_table(unsigned target,
}
 }
 
-#define reg_to_match_value(x)  \
-   ({  \
-   unsigned long val;  \
-   val  = (x)->Op0 << 14;  \
-   val |= (x)->Op1 << 11;  \
-   val |= (x)->CRn << 7;   \
-   val |= (x)->CRm << 3;   \
-   val |= (x)->Op2;\
-   val;\
-})
-
-static int match_sys_reg(const void *key, const void *elt)
-{
-   const unsigned long pval = (unsigned long)key;
-   const struct sys_reg_desc *r = elt;
-
-   return pval - reg_to_match_value(r);
-}
-
-static const struct sys_reg_desc *find_reg(const struct sys_reg_params *params,
-const struct sys_reg_desc table[],
-unsigned int num)
-{
-   unsigned long pval = reg_to_match_value(params);
-
-   return bsearch((void *)pval, table, num, sizeof(table[0]), 
match_sys_reg);
-}
-
 int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
kvm_inject_undefined(vcpu);
return 1;
 }
 
-static void perform_access(struct kvm_vcpu *vcpu,
-  struct sys_reg_params *params,
-  const struct sys_reg_desc *r)
-{
-   /*
-* Not having an accessor means that we have configured a trap
-* that we don't know how to handle. This certainly qualifies
-* as a gross bug that should be fixed right away.
-*/
-   BUG_ON(!r->access);
-
-   /* Skip instruction if instructed so */
-   if (likely(r->access(vcpu, params, r)))
-   kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
-}
-
 /*
  * emulate_cp --  tries to match a sys

[RFC PATCH v2 22/31] KVM: arm64: Emulate AT S1E2 instructions

2017-10-02 Thread Jintack Lim
Emulate AT S1E2 instructions by issuing the corresponding S1E1
instructions in EL2. We set the physical EL1 registers and the HCR_EL2
register as described in the AT instruction emulation overview.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 19 +--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index a82274f..cb46db5 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1641,6 +1641,21 @@ static bool handle_s1e01(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
return true;
 }
 
+static bool handle_s1e2(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+   const struct sys_reg_desc *r)
+{
+   struct kvm_cpu_context *ctxt = >arch.ctxt;
+   bool el2_format;
+   int sys_encoding = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
+
+   /* See the '1. EL2 AT instructions: S1E2x' table */
+   ctxt->hw_sys_regs = ctxt->shadow_sys_regs;
+   el2_format = !vcpu_el2_e2h_is_set(vcpu);
+
+   kvm_call_hyp(__kvm_at_insn, vcpu, p->regval, el2_format, sys_encoding);
+   return true;
+}
+
 /*
  * AT instruction emulation
  *
@@ -1716,8 +1731,8 @@ static bool handle_s1e01(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
SYS_INSN_TO_DESC(AT_S1E0W, handle_s1e01, NULL),
SYS_INSN_TO_DESC(AT_S1E1RP, handle_s1e01, NULL),
SYS_INSN_TO_DESC(AT_S1E1WP, handle_s1e01, NULL),
-   SYS_INSN_TO_DESC(AT_S1E2R, NULL, NULL),
-   SYS_INSN_TO_DESC(AT_S1E2W, NULL, NULL),
+   SYS_INSN_TO_DESC(AT_S1E2R, handle_s1e2, NULL),
+   SYS_INSN_TO_DESC(AT_S1E2W, handle_s1e2, NULL),
SYS_INSN_TO_DESC(AT_S12E1R, NULL, NULL),
SYS_INSN_TO_DESC(AT_S12E1W, NULL, NULL),
SYS_INSN_TO_DESC(AT_S12E0R, NULL, NULL),
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 18/31] KVM: arm64: Enumerate AT and TLBI instructions to emulate

2017-10-02 Thread Jintack Lim
List all system instructions to emulate. This patch only introduces the
definitions, emulation handlers will be added in subsequent patches.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/sysreg.h | 38 ++
 arch/arm64/kvm/sys_regs.c   | 26 ++
 2 files changed, 64 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index a051d42..53df733 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -367,6 +367,44 @@
 
 #define SYS_SP_EL2 sys_reg(3, 6, 4, 1, 0)
 
+/* AT instructions */
+#define AT_Op0 1
+#define AT_CRn 7
+
+#define AT_S1E1R   sys_insn(AT_Op0, 0, AT_CRn, 8, 0)
+#define AT_S1E1W   sys_insn(AT_Op0, 0, AT_CRn, 8, 1)
+#define AT_S1E0R   sys_insn(AT_Op0, 0, AT_CRn, 8, 2)
+#define AT_S1E0W   sys_insn(AT_Op0, 0, AT_CRn, 8, 3)
+#define AT_S1E1RP  sys_insn(AT_Op0, 0, AT_CRn, 9, 0)
+#define AT_S1E1WP  sys_insn(AT_Op0, 0, AT_CRn, 9, 1)
+#define AT_S1E2R   sys_insn(AT_Op0, 4, AT_CRn, 8, 0)
+#define AT_S1E2W   sys_insn(AT_Op0, 4, AT_CRn, 8, 1)
+#define AT_S12E1R  sys_insn(AT_Op0, 4, AT_CRn, 8, 4)
+#define AT_S12E1W  sys_insn(AT_Op0, 4, AT_CRn, 8, 5)
+#define AT_S12E0R  sys_insn(AT_Op0, 4, AT_CRn, 8, 6)
+#define AT_S12E0W  sys_insn(AT_Op0, 4, AT_CRn, 8, 7)
+
+/* TLBI instructions */
+#define TLBI_Op0   1
+#define TLBI_Op1_EL2   4   /* Accessible from EL2 or higher */
+#define TLBI_CRn   8
+#define tlbi_insn_el2(CRm, Op2)sys_insn(TLBI_Op0, TLBI_Op1_EL2, 
TLBI_CRn, (CRm), (Op2))
+
+#define TLBI_IPAS2E1IS tlbi_insn_el2(0, 1)
+#define TLBI_IPAS2LE1IStlbi_insn_el2(0, 5)
+#define TLBI_ALLE2IS   tlbi_insn_el2(3, 0)
+#define TLBI_VAE2IStlbi_insn_el2(3, 1)
+#define TLBI_ALLE1IS   tlbi_insn_el2(3, 4)
+#define TLBI_VALE2IS   tlbi_insn_el2(3, 5)
+#define TLBI_VMALLS12E1IS  tlbi_insn_el2(3, 6)
+#define TLBI_IPAS2E1   tlbi_insn_el2(4, 1)
+#define TLBI_IPAS2LE1  tlbi_insn_el2(4, 5)
+#define TLBI_ALLE2 tlbi_insn_el2(7, 0)
+#define TLBI_VAE2  tlbi_insn_el2(7, 1)
+#define TLBI_ALLE1 tlbi_insn_el2(7, 4)
+#define TLBI_VALE2 tlbi_insn_el2(7, 5)
+#define TLBI_VMALLS12E1tlbi_insn_el2(7, 6)
+
 /* Common SCTLR_ELx flags. */
 #define SCTLR_ELx_EE(1 << 25)
 #define SCTLR_ELx_I(1 << 12)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 481bea64..8d04926 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1624,6 +1624,32 @@ static bool access_id_aa64mmfr0_el1(struct kvm_vcpu *v,
 #define SYS_INSN_TO_DESC(insn, access_fn, forward_fn)  \
{ SYS_DESC((insn)), (access_fn), NULL, 0, 0, NULL, NULL, (forward_fn) }
 static struct sys_reg_desc sys_insn_descs[] = {
+   SYS_INSN_TO_DESC(AT_S1E1R, NULL, NULL),
+   SYS_INSN_TO_DESC(AT_S1E1W, NULL, NULL),
+   SYS_INSN_TO_DESC(AT_S1E0R, NULL, NULL),
+   SYS_INSN_TO_DESC(AT_S1E0W, NULL, NULL),
+   SYS_INSN_TO_DESC(AT_S1E1RP, NULL, NULL),
+   SYS_INSN_TO_DESC(AT_S1E1WP, NULL, NULL),
+   SYS_INSN_TO_DESC(AT_S1E2R, NULL, NULL),
+   SYS_INSN_TO_DESC(AT_S1E2W, NULL, NULL),
+   SYS_INSN_TO_DESC(AT_S12E1R, NULL, NULL),
+   SYS_INSN_TO_DESC(AT_S12E1W, NULL, NULL),
+   SYS_INSN_TO_DESC(AT_S12E0R, NULL, NULL),
+   SYS_INSN_TO_DESC(AT_S12E0W, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_IPAS2E1IS, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_IPAS2LE1IS, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_ALLE2IS, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_VAE2IS, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_ALLE1IS, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_VALE2IS, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_VMALLS12E1IS, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_IPAS2E1, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_IPAS2LE1, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_ALLE2, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_VAE2, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_ALLE1, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_VALE2, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_VMALLS12E1, NULL, NULL),
 };
 
 #define reg_to_match_value(x)  \
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 20/31] KVM: arm64: Implement AT instruction handling

2017-10-02 Thread Jintack Lim
Implement AT instruction handling logic in EL2. This will be used to
emulate AT instructions executed in the virtual EL2.

AT instruction emulation works by loading the proper processor context,
which depends on the trapped instruction and the virtual HCR_EL2, to the
EL1 virtual memory control registers and executing AT instructions. Note
that ctxt->hw_sys_regs is expected to have the proper processor context
before calling the handling function(__kvm_at_insn) implemented in this
patch.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_asm.h |   3 +
 arch/arm64/kvm/hyp/Makefile  |   1 +
 arch/arm64/kvm/hyp/at.c  | 131 +++
 3 files changed, 135 insertions(+)
 create mode 100644 arch/arm64/kvm/hyp/at.c

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index e492749..4bded9d 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -56,6 +56,9 @@
 extern void __kvm_tlb_flush_vmid(u64 vttbr);
 extern void __kvm_tlb_flush_local_vmid(u64 vttbr);
 
+extern void __kvm_at_insn(struct kvm_vcpu *vcpu, unsigned long vaddr,
+ bool el2_regime, int sys_encoding);
+
 extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
 
 extern u64 __vgic_v3_get_ich_vtr_el2(void);
diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
index 14c4e3b..1b03adb 100644
--- a/arch/arm64/kvm/hyp/Makefile
+++ b/arch/arm64/kvm/hyp/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_KVM_ARM_HOST) += entry.o
 obj-$(CONFIG_KVM_ARM_HOST) += switch.o
 obj-$(CONFIG_KVM_ARM_HOST) += fpsimd.o
 obj-$(CONFIG_KVM_ARM_HOST) += tlb.o
+obj-$(CONFIG_KVM_ARM_HOST) += at.o
 obj-$(CONFIG_KVM_ARM_HOST) += hyp-entry.o
 obj-$(CONFIG_KVM_ARM_HOST) += s2-setup.o
 
diff --git a/arch/arm64/kvm/hyp/at.c b/arch/arm64/kvm/hyp/at.c
new file mode 100644
index 000..d491d94
--- /dev/null
+++ b/arch/arm64/kvm/hyp/at.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2017 - Linaro Ltd
+ * Author: Jintack Lim <jintack@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include 
+
+static void __hyp_text __save_vmregs(struct kvm_cpu_context *ctxt)
+{
+   u64 *sys_regs = kern_hyp_va(ctxt->hw_sys_regs);
+
+   sys_regs[TTBR0_EL1] = read_sysreg_el1(ttbr0);
+   sys_regs[TTBR1_EL1] = read_sysreg_el1(ttbr1);
+   sys_regs[TCR_EL1]   = read_sysreg_el1(tcr);
+   sys_regs[SCTLR_EL1] = read_sysreg_el1(sctlr);
+}
+
+static void __hyp_text __restore_vmregs(struct kvm_cpu_context *ctxt)
+{
+   u64 *sys_regs = kern_hyp_va(ctxt->hw_sys_regs);
+
+   write_sysreg_el1(sys_regs[TTBR0_EL1],   ttbr0);
+   write_sysreg_el1(sys_regs[TTBR1_EL1],   ttbr1);
+   write_sysreg_el1(sys_regs[TCR_EL1], tcr);
+   write_sysreg_el1(sys_regs[SCTLR_EL1],   sctlr);
+}
+
+void __hyp_text __at_switch_to_guest_nvhe(struct kvm_vcpu *vcpu,
+ bool el2_regime)
+{
+   struct kvm_cpu_context *host_ctxt;
+   struct kvm_cpu_context *guest_ctxt;
+   u64 val;
+
+   host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+   guest_ctxt = >arch.ctxt;
+
+   __save_vmregs(host_ctxt);
+   __restore_vmregs(guest_ctxt);
+
+   val = read_sysreg(hcr_el2);
+   if (el2_regime)
+   val |= (HCR_NV | HCR_NV1);
+   write_sysreg(val, hcr_el2);
+}
+
+void __hyp_text __at_switch_to_guest_vhe(struct kvm_vcpu *vcpu, bool 
el2_regime)
+{
+   struct kvm_cpu_context *guest_ctxt = >arch.ctxt;
+   u64 val;
+
+   __restore_vmregs(guest_ctxt);
+
+   val = read_sysreg(hcr_el2);
+   val &= ~HCR_TGE;
+   if (el2_regime)
+   val |= (HCR_NV | HCR_NV1);
+   write_sysreg(val, hcr_el2);
+}
+
+/*
+ * Switching to guest.
+ *
+ * 1. [nvhe] Save host vm regs
+ * 2. [both] Restore guest vm regs
+ * 3. [both] Set HCR_EL2.NV/NV1 bit if necessary
+ * 4. [vhe]  Clear HCR_EL2.TGE
+ */
+static hyp_alternate_select(__at_switch_to_guest,
+   __at_switch_to_guest_nvhe, __at_switch_to_guest_vhe,
+   ARM64_HAS_VIRT_HOST_EXTN);
+
+void __hyp_text __kvm_at_insn(struct kvm_vcpu *vcpu, unsigned long vaddr,
+ bool el2_regime, int sys_encoding)
+{
+   struct kvm_cpu_context *ctxt = >arch.ctxt;
+   struct kvm_cpu_context *host_ctxt;
+
+   host_ctx

[RFC PATCH v2 25/31] KVM: arm64: Emulate TLBI VAE2* instrutions

2017-10-02 Thread Jintack Lim
Emulate TLBI VAE2* instruction executed in the virtual EL2. Based on the
same principle as TLBI ALLE2 instruction, we can simply emulate those
instructions by executing corresponding VAE1* instructions with the
virtual EL2's VMID assigned by the host hypervisor.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_asm.h |  1 +
 arch/arm64/kvm/hyp/tlb.c | 28 
 arch/arm64/kvm/sys_regs.c| 25 +
 3 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 4bded9d..cd7fb85 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -55,6 +55,7 @@
 extern void __kvm_tlb_flush_vmid_ipa(u64 vttbr, phys_addr_t ipa);
 extern void __kvm_tlb_flush_vmid(u64 vttbr);
 extern void __kvm_tlb_flush_local_vmid(u64 vttbr);
+extern void __kvm_tlb_vae2(u64 vttbr, u64 va, u64 sys_encoding);
 
 extern void __kvm_at_insn(struct kvm_vcpu *vcpu, unsigned long vaddr,
  bool el2_regime, int sys_encoding);
diff --git a/arch/arm64/kvm/hyp/tlb.c b/arch/arm64/kvm/hyp/tlb.c
index 680b960..bd8b92c 100644
--- a/arch/arm64/kvm/hyp/tlb.c
+++ b/arch/arm64/kvm/hyp/tlb.c
@@ -151,3 +151,31 @@ void __hyp_text __kvm_flush_vm_context(void)
asm volatile("ic ialluis" : : );
dsb(ish);
 }
+
+void __hyp_text __kvm_tlb_vae2(u64 vttbr, u64 va, u64 sys_encoding)
+{
+   /* Switch to requested VMID */
+   __tlb_switch_to_guest()(vttbr);
+
+   /* Execute the EL1 version of TLBI VAE2* instruction */
+   switch (sys_encoding) {
+   case TLBI_VAE2IS:
+   __tlbi(vae1is, va);
+   break;
+   case TLBI_VALE2IS:
+   __tlbi(vale1is, va);
+   break;
+   case TLBI_VAE2:
+   __tlbi(vae1, va);
+   break;
+   case TLBI_VALE2:
+   __tlbi(vale1, va);
+   break;
+   default:
+   break;
+   }
+   dsb(nsh);
+   isb();
+
+   __tlb_switch_to_host()();
+}
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 90329b7..a1ae8fb 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1778,6 +1778,23 @@ static bool handle_alle2is(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
return true;
 }
 
+static bool handle_vae2(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+  const struct sys_reg_desc *r)
+{
+   struct kvm_s2_mmu *mmu = >kvm->arch.mmu;
+   u64 vttbr = kvm_get_vttbr(>el2_vmid, mmu);
+   int sys_encoding = sys_insn(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
+
+   /*
+* Based on the same principle as TLBI ALLE2 instruction emulation, we
+* emulate TLBI VAE2* instructions by executing corresponding TLBI VAE1*
+* instructions with the virtual EL2's VMID assigned by the host
+* hypervisor.
+*/
+   kvm_call_hyp(__kvm_tlb_vae2, vttbr, p->regval, sys_encoding);
+   return true;
+}
+
 /*
  * AT instruction emulation
  *
@@ -1862,16 +1879,16 @@ static bool handle_alle2is(struct kvm_vcpu *vcpu, 
struct sys_reg_params *p,
SYS_INSN_TO_DESC(TLBI_IPAS2E1IS, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_IPAS2LE1IS, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_ALLE2IS, handle_alle2is, NULL),
-   SYS_INSN_TO_DESC(TLBI_VAE2IS, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_VAE2IS, handle_vae2, NULL),
SYS_INSN_TO_DESC(TLBI_ALLE1IS, NULL, NULL),
-   SYS_INSN_TO_DESC(TLBI_VALE2IS, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_VALE2IS, handle_vae2, NULL),
SYS_INSN_TO_DESC(TLBI_VMALLS12E1IS, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_IPAS2E1, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_IPAS2LE1, NULL, NULL),
SYS_INSN_TO_DESC(TLBI_ALLE2, handle_alle2, NULL),
-   SYS_INSN_TO_DESC(TLBI_VAE2, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_VAE2, handle_vae2, NULL),
SYS_INSN_TO_DESC(TLBI_ALLE1, NULL, NULL),
-   SYS_INSN_TO_DESC(TLBI_VALE2, NULL, NULL),
+   SYS_INSN_TO_DESC(TLBI_VALE2, handle_vae2, NULL),
SYS_INSN_TO_DESC(TLBI_VMALLS12E1, NULL, NULL),
 };
 
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 17/31] KVM: arm64: Rework the system instruction emulation framework

2017-10-02 Thread Jintack Lim
Rework the system instruction emulation framework to handle potentially
all system instruction traps other than MSR/MRS instructions. Those
system instructions would be AT and TLBI instructions controlled by
HCR_EL2.NV, AT, and TTLB bits.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 66 ++-
 1 file changed, 25 insertions(+), 41 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 88ce172..481bea64 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1621,6 +1621,11 @@ static bool access_id_aa64mmfr0_el1(struct kvm_vcpu *v,
{ SYS_DESC(SYS_SP_EL2), NULL, reset_special, SP_EL2, 0},
 };
 
+#define SYS_INSN_TO_DESC(insn, access_fn, forward_fn)  \
+   { SYS_DESC((insn)), (access_fn), NULL, 0, 0, NULL, NULL, (forward_fn) }
+static struct sys_reg_desc sys_insn_descs[] = {
+};
+
 #define reg_to_match_value(x)  \
({  \
unsigned long val;  \
@@ -1674,6 +1679,25 @@ static void perform_access(struct kvm_vcpu *vcpu,
kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
 }
 
+static int emulate_sys_instr(struct kvm_vcpu *vcpu, struct sys_reg_params *p)
+{
+
+   const struct sys_reg_desc *r;
+
+   /* Search from the system instruction table. */
+   r = find_reg(p, sys_insn_descs, ARRAY_SIZE(sys_insn_descs));
+
+   if (likely(r)) {
+   perform_access(vcpu, p, r);
+   } else {
+   kvm_err("Unsupported guest sys instruction at: %lx\n",
+   *vcpu_pc(vcpu));
+   print_sys_reg_instr(p);
+   kvm_inject_undefined(vcpu);
+   }
+   return 1;
+}
+
 static bool trap_dbgidr(struct kvm_vcpu *vcpu,
struct sys_reg_params *p,
const struct sys_reg_desc *r)
@@ -2236,47 +2260,6 @@ static int emulate_sys_reg(struct kvm_vcpu *vcpu,
return 1;
 }
 
-static int emulate_tlbi(struct kvm_vcpu *vcpu,
-struct sys_reg_params *params)
-{
-   /* TODO: support tlbi instruction emulation*/
-   kvm_inject_undefined(vcpu);
-   return 1;
-}
-
-static int emulate_at(struct kvm_vcpu *vcpu,
-struct sys_reg_params *params)
-{
-   /* TODO: support address translation instruction emulation */
-   kvm_inject_undefined(vcpu);
-   return 1;
-}
-
-static int emulate_sys_instr(struct kvm_vcpu *vcpu,
-struct sys_reg_params *params)
-{
-   int ret = 0;
-
-   /*
-* Forward this trap to the virtual EL2 if the virtual HCR_EL2.NV
-* bit is set.
-*/
-   if (forward_nv_traps(vcpu))
-   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
-
-   /* TLB maintenance instructions*/
-   if (params->CRn == 0b1000)
-   ret = emulate_tlbi(vcpu, params);
-   /* Address Translation instructions */
-   else if (params->CRn == 0b0111 && params->CRm == 0b1000)
-   ret = emulate_at(vcpu, params);
-
-   if (ret)
-   kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
-
-   return ret;
-}
-
 static void reset_sys_reg_descs(struct kvm_vcpu *vcpu,
  const struct sys_reg_desc *table, size_t num)
 {
@@ -2754,6 +2737,7 @@ void kvm_sys_reg_table_init(void)
BUG_ON(check_sysreg_table(cp15_regs, ARRAY_SIZE(cp15_regs)));
BUG_ON(check_sysreg_table(cp15_64_regs, ARRAY_SIZE(cp15_64_regs)));
BUG_ON(check_sysreg_table(invariant_sys_regs, 
ARRAY_SIZE(invariant_sys_regs)));
+   BUG_ON(check_sysreg_table(sys_insn_descs, ARRAY_SIZE(sys_insn_descs)));
 
/* We abuse the reset function to overwrite the table itself. */
for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++)
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 19/31] KVM: arm64: Describe AT instruction emulation design

2017-10-02 Thread Jintack Lim
This design overview will help to digest the subsequent patches that
implement AT instruction emulation.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 66 +++
 1 file changed, 66 insertions(+)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 8d04926..d8728cc 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1621,6 +1621,72 @@ static bool access_id_aa64mmfr0_el1(struct kvm_vcpu *v,
{ SYS_DESC(SYS_SP_EL2), NULL, reset_special, SP_EL2, 0},
 };
 
+/*
+ * AT instruction emulation
+ *
+ * We emulate AT instructions executed in the virtual EL2.
+ * Basic strategy for the stage-1 translation emulation is to load proper
+ * context, which depends on the trapped instruction and the virtual HCR_EL2,
+ * to the EL1 virtual memory control registers and execute S1E[01] instructions
+ * in EL2. See below for more detail.
+ *
+ * For the stage-2 translation, which is necessary for S12E[01] emulation,
+ * we walk the guest hypervisor's stage-2 page table in software.
+ *
+ * The stage-1 translation emulations can be divided into two groups depending
+ * on the translation regime.
+ *
+ * 1. EL2 AT instructions: S1E2x
+ * +---+
+ * | | Setting for the emulation   |
+ * | Virtual HCR_EL2.E2H on trap |-+
+ * | | Phys EL1 regs | Phys NV, NV1 | Phys TGE |
+ * |---|
+ * | 0   | vEL2  |(1, 1)|0 |
+ * | 1   | vEL2  |(0, 0)|0 |
+ * +---+
+ *
+ * We emulate the EL2 AT instructions by loading virtual EL2 context
+ * to the EL1 virtual memory control registers and executing corresponding
+ * EL1 AT instructions.
+ *
+ * We set physical NV and NV1 bits to use EL2 page table format for non-VHE
+ * guest hypervisor (i.e. HCR_EL2.E2H == 0). As a VHE guest hypervisor uses the
+ * EL1 page table format, we don't set those bits.
+ *
+ * We should clear physical TGE bit not to use the EL2 translation regime when
+ * the host uses the VHE feature.
+ *
+ *
+ * 2. EL0/EL1 AT instructions: S1E[01]x, S12E1x
+ * +--+
+ * |   Virtual HCR_EL2 on trap  |Setting for the emulation|
+ * |--+
+ * | (vE2H, vTGE) | (vNV, vNV1) | Phys EL1 regs | Phys NV, NV1 | Phys TGE |
+ * |--|
+ * |(0, 0)*   |   (0, 0)|  vEL1 |(0, 0)|0 |
+ * |(0, 0)|   (1, 1)|  vEL1 |(1, 1)|0 |
+ * |(1, 1)|   (0, 0)|  vEL2 |(0, 0)|0 |
+ * |(1, 1)|   (1, 1)|  vEL2 |(1, 1)|0 |
+ * +--+
+ *
+ * *For (0, 0) in the 'Virtual HCR_EL2 on trap' column, it actually means
+ *  (1, 1). Keep them (0, 0) just for the readability.
+ *
+ * We set physical EL1 virtual memory control registers depending on
+ * (vE2H, vTGE) pair. When the pair is (0, 0) where AT instructions are
+ * supposed to use EL0/EL1 translation regime, we load the EL1 registers with
+ * the virtual EL1 registers (i.e. EL1 registers from the guest hypervisor's
+ * point of view). When the pair is (1, 1), however, AT instructions are 
defined
+ * to apply EL2 translation regime. To emulate this behavior, we load the EL1
+ * registers with the virtual EL2 context. (i.e the shadow registers)
+ *
+ * We respect the virtual NV and NV1 bit for the emulation. When those bits are
+ * set, it means that a guest hypervisor would like to use EL2 page table 
format
+ * for the EL1 translation regime. We emulate this by setting the physical
+ * NV and NV1 bits.
+ */
+
 #define SYS_INSN_TO_DESC(insn, access_fn, forward_fn)  \
{ SYS_DESC((insn)), (access_fn), NULL, 0, 0, NULL, NULL, (forward_fn) }
 static struct sys_reg_desc sys_insn_descs[] = {
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 05/31] KVM: arm/arm64: Support mmu for the virtual EL2 execution

2017-10-02 Thread Jintack Lim
From: Christoffer Dall <christoffer.d...@linaro.org>

When running a guest hypervisor in virtual EL2, the translation context
has to be separate from the rest of the system, including the guest
EL1/0 translation regime, so we allocate a separate VMID for this mode.

Considering that we have two different vttbr values due to separate
VMIDs, it's racy to keep a vttbr value in a struct (kvm_s2_mmu) and
share it between multiple vcpus. So, remove the shared vttbr field, and
set up per-vcpu hw_vttbr field.

Hypercalls to flush tlb now have vttbr as a parameter instead of mmu,
since mmu structure does not have vttbr any more.

Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Jintack Lim <jintack@linaro.org>
---

Notes:
v1-->v2:
Fixed a bug that hw_vttbr was not initialized correctly in 
kvm_arch_vcpu_init()
where vmid is not allocated yet. This prevented the guest from booting on 
32bit
arm; hw_vttbr is set on each entry on aarch64, so it was fine.

 arch/arm/include/asm/kvm_asm.h   |  6 ++--
 arch/arm/include/asm/kvm_emulate.h   |  4 +++
 arch/arm/include/asm/kvm_host.h  | 14 +---
 arch/arm/include/asm/kvm_mmu.h   | 11 ++
 arch/arm/kvm/hyp/switch.c|  4 +--
 arch/arm/kvm/hyp/tlb.c   | 15 -
 arch/arm64/include/asm/kvm_asm.h |  6 ++--
 arch/arm64/include/asm/kvm_emulate.h |  8 +
 arch/arm64/include/asm/kvm_host.h| 14 +---
 arch/arm64/include/asm/kvm_mmu.h | 11 ++
 arch/arm64/kvm/hyp/switch.c  |  4 +--
 arch/arm64/kvm/hyp/tlb.c | 34 +--
 virt/kvm/arm/arm.c   | 65 +---
 virt/kvm/arm/mmu.c   |  9 +++--
 14 files changed, 128 insertions(+), 77 deletions(-)

diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index 71b7255..23a79bd 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -65,9 +65,9 @@
 extern char __kvm_hyp_vector[];
 
 extern void __kvm_flush_vm_context(void);
-extern void __kvm_tlb_flush_vmid_ipa(struct kvm_s2_mmu *mmu, phys_addr_t ipa);
-extern void __kvm_tlb_flush_vmid(struct kvm_s2_mmu *mmu);
-extern void __kvm_tlb_flush_local_vmid(struct kvm_s2_mmu *mmu);
+extern void __kvm_tlb_flush_vmid_ipa(u64 vttbr, phys_addr_t ipa);
+extern void __kvm_tlb_flush_vmid(u64 vttbr);
+extern void __kvm_tlb_flush_local_vmid(u64 vttbr);
 
 extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
 
diff --git a/arch/arm/include/asm/kvm_emulate.h 
b/arch/arm/include/asm/kvm_emulate.h
index 29a4dec..24a3fbf 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -293,4 +293,8 @@ static inline unsigned long vcpu_data_host_to_guest(struct 
kvm_vcpu *vcpu,
}
 }
 
+static inline struct kvm_s2_vmid *vcpu_get_active_vmid(struct kvm_vcpu *vcpu)
+{
+   return >kvm->arch.mmu.vmid;
+}
 #endif /* __ARM_KVM_EMULATE_H__ */
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 78d826e..33ccdbe 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -53,16 +53,18 @@
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
 void kvm_reset_coprocs(struct kvm_vcpu *vcpu);
 
-struct kvm_s2_mmu {
+struct kvm_s2_vmid {
/* The VMID generation used for the virt. memory system */
u64vmid_gen;
u32vmid;
+};
+
+struct kvm_s2_mmu {
+   struct kvm_s2_vmid vmid;
+   struct kvm_s2_vmid el2_vmid;
 
/* Stage-2 page table */
pgd_t *pgd;
-
-   /* VTTBR value associated with above pgd and vmid */
-   u64vttbr;
 };
 
 struct kvm_arch {
@@ -193,6 +195,9 @@ struct kvm_vcpu_arch {
 
/* Stage 2 paging state used by the hardware on next switch */
struct kvm_s2_mmu *hw_mmu;
+
+   /* VTTBR value used by the hardware on next switch */
+   u64 hw_vttbr;
 };
 
 struct kvm_vm_stat {
@@ -239,6 +244,7 @@ static inline void 
kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
 {
 }
 
+unsigned int get_kvm_vmid_bits(void);
 struct kvm_vcpu *kvm_arm_get_running_vcpu(void);
 struct kvm_vcpu __percpu **kvm_get_running_vcpus(void);
 void kvm_arm_halt_guest(struct kvm *kvm);
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index fa6f217..86fdc70 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -221,6 +221,17 @@ static inline unsigned int kvm_get_vmid_bits(void)
return 8;
 }
 
+static inline u64 kvm_get_vttbr(struct kvm_s2_vmid *vmid,
+   struct kvm_s2_mmu *mmu)
+{
+   u64 vmid_field, baddr;
+
+   baddr = virt_to_phys(mmu->pgd);
+   vmid_field = ((u64)vmid->vmid << VTTBR_VMID_SHIFT) &
+   VTTBR_VMID_MASK(get_kvm_vmid_bits());
+   return baddr | vmid_field;
+}
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __ARM_KVM_MMU_H__ */
diff --git a/arch/arm/kvm/hyp

[RFC PATCH v2 12/31] KVM: arm/arm64: Handle shadow stage 2 page faults

2017-10-02 Thread Jintack Lim
From: Christoffer Dall <christoffer.d...@linaro.org>

If we are faulting on a shadow stage 2 translation, we first walk the
guest hypervisor's stage 2 page table to see if it has a mapping. If
not, we inject a stage 2 page fault to the virtual EL2. Otherwise, we
create a mapping in the shadow stage 2 page table.

Note that we have to deal with two IPAs when we got a showdow stage 2
page fault. One is the address we faulted on, and is in the L2 guest
phys space. The other is from the guest stage-2 page table walk, and is
in the L1 guest phys space.  To differentiate them, we rename variable
names so that fault_ipa is used for the former and ipa is used for the
latter.

Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Jintack Lim <jintack@linaro.org>
---

Notes:
v1-->v2:
- Added a common function to inject s2 faults.
- Align L1 IPA as well as L2 IPA in transparent_hugepage_adjust(). This will
come in handy when creating a rmap entry with both IPAs.

 arch/arm/include/asm/kvm_emulate.h   |  7 
 arch/arm/include/asm/kvm_mmu.h   |  4 ++
 arch/arm64/include/asm/kvm_emulate.h |  5 +++
 arch/arm64/include/asm/kvm_mmu.h |  1 +
 arch/arm64/kvm/mmu-nested.c  |  8 
 virt/kvm/arm/mmio.c  | 12 +++---
 virt/kvm/arm/mmu.c   | 75 +---
 7 files changed, 92 insertions(+), 20 deletions(-)

diff --git a/arch/arm/include/asm/kvm_emulate.h 
b/arch/arm/include/asm/kvm_emulate.h
index 24a3fbf..8136464 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -297,4 +297,11 @@ static inline struct kvm_s2_vmid 
*vcpu_get_active_vmid(struct kvm_vcpu *vcpu)
 {
return >kvm->arch.mmu.vmid;
 }
+
+/* arm architecture doesn't support the nesting */
+static inline bool kvm_is_shadow_s2_fault(struct kvm_vcpu *vcpu)
+{
+   return false;
+}
+
 #endif /* __ARM_KVM_EMULATE_H__ */
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 5fab21a..6a22846 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -242,6 +242,10 @@ static inline void kvm_nested_s2_free(struct kvm *kvm) { }
 static inline void kvm_nested_s2_wp(struct kvm *kvm) { }
 static inline void kvm_nested_s2_clear(struct kvm *kvm) { }
 static inline void kvm_nested_s2_flush(struct kvm *kvm) { }
+static inline int kvm_inject_s2_fault(struct kvm_vcpu *vcpu, u64 esr_el2)
+{
+   return 0;
+}
 
 static inline u64 kvm_get_vttbr(struct kvm_s2_vmid *vmid,
struct kvm_s2_mmu *mmu)
diff --git a/arch/arm64/include/asm/kvm_emulate.h 
b/arch/arm64/include/asm/kvm_emulate.h
index f476576..c66554b 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -390,4 +390,9 @@ static inline unsigned long vcpu_data_host_to_guest(struct 
kvm_vcpu *vcpu,
return data;/* Leave LE untouched */
 }
 
+static inline bool kvm_is_shadow_s2_fault(struct kvm_vcpu *vcpu)
+{
+   return vcpu_nested_stage2_enabled(vcpu) && !is_hyp_ctxt(vcpu);
+}
+
 #endif /* __ARM64_KVM_EMULATE_H__ */
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index c4efcd5..425e4a2 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -342,6 +342,7 @@ int kvm_walk_nested_s2(struct kvm_vcpu *vcpu, phys_addr_t 
gipa,
 void kvm_nested_s2_wp(struct kvm *kvm);
 void kvm_nested_s2_clear(struct kvm *kvm);
 void kvm_nested_s2_flush(struct kvm *kvm);
+int kvm_inject_s2_fault(struct kvm_vcpu *vcpu, u64 esr_el2);
 
 static inline u64 kvm_get_vttbr(struct kvm_s2_vmid *vmid,
struct kvm_s2_mmu *mmu)
diff --git a/arch/arm64/kvm/mmu-nested.c b/arch/arm64/kvm/mmu-nested.c
index fb694b7..75570cc 100644
--- a/arch/arm64/kvm/mmu-nested.c
+++ b/arch/arm64/kvm/mmu-nested.c
@@ -60,6 +60,14 @@ static int esr_s2_fault(struct kvm_vcpu *vcpu, int level, 
u32 fsc)
return esr;
 }
 
+int kvm_inject_s2_fault(struct kvm_vcpu *vcpu, u64 esr_el2)
+{
+   vcpu->arch.ctxt.sys_regs[FAR_EL2] = vcpu->arch.fault.far_el2;
+   vcpu->arch.ctxt.sys_regs[HPFAR_EL2] = vcpu->arch.fault.hpfar_el2;
+
+   return kvm_inject_nested_sync(vcpu, esr_el2);
+}
+
 static int check_base_s2_limits(struct kvm_vcpu *vcpu, struct s2_walk_info *wi,
int level, int input_size, int stride)
 {
diff --git a/virt/kvm/arm/mmio.c b/virt/kvm/arm/mmio.c
index b6e715f..a1009c2 100644
--- a/virt/kvm/arm/mmio.c
+++ b/virt/kvm/arm/mmio.c
@@ -153,7 +153,7 @@ static int decode_hsr(struct kvm_vcpu *vcpu, bool 
*is_write, int *len)
 }
 
 int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
-phys_addr_t fault_ipa)
+phys_addr_t ipa)
 {
unsigned long data;
unsigned long rt;
@@ -182,22 +182,22 @@ int io_mem_abort(struct kvm_vcpu *v

[RFC PATCH v2 11/31] KVM: arm64: Implement nested Stage-2 page table walk logic

2017-10-02 Thread Jintack Lim
From: Christoffer Dall <christoffer.d...@linaro.org>

Based on the pseudo-code in the ARM ARM, implement a stage 2 software
page table walker.

Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Jintack Lim <jintack@linaro.org>
---

Notes:
v1-->v2:
- Handled different endianness between the host and the guest hypervisor
- Decoupled the stage-2 PTW from injecting exceptions. This will come in 
handy
  when we just want to walk the page table.
- Added esr and upper_attr fields in kvm_s2_trans struct
- Reworked pa_max() to have KVM_PHYS_SHIFT
- Updated comment about the continuous bits

 arch/arm/include/asm/kvm_mmu.h   |  16 +++
 arch/arm64/include/asm/esr.h |   1 +
 arch/arm64/include/asm/kvm_arm.h |   3 +
 arch/arm64/include/asm/kvm_mmu.h |  12 ++
 arch/arm64/kvm/mmu-nested.c  | 241 +++
 5 files changed, 273 insertions(+)

diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index d3eafc5..5fab21a 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -221,6 +221,22 @@ static inline unsigned int kvm_get_vmid_bits(void)
return 8;
 }
 
+struct kvm_s2_trans {
+   phys_addr_t output;
+   phys_addr_t block_size;
+   bool writable;
+   bool readable;
+   int level;
+   u32 esr;
+   u64 upper_attr;
+};
+
+static inline int kvm_walk_nested_s2(struct kvm_vcpu *vcpu, phys_addr_t gipa,
+struct kvm_s2_trans *result)
+{
+   return 0;
+}
+
 static inline void kvm_nested_s2_unmap(struct kvm_vcpu *vcpu) { }
 static inline void kvm_nested_s2_free(struct kvm *kvm) { }
 static inline void kvm_nested_s2_wp(struct kvm *kvm) { }
diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index 210fde6..bc6610b 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -108,6 +108,7 @@
 #define ESR_ELx_CM (UL(1) << 8)
 
 /* ISS field definitions for exceptions taken in to Hyp */
+#define ESR_ELx_FSC_ADDRSZ (0x00)
 #define ESR_ELx_CV (UL(1) << 24)
 #define ESR_ELx_COND_SHIFT (20)
 #define ESR_ELx_COND_MASK  (UL(0xF) << ESR_ELx_COND_SHIFT)
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index a1274b7..3993703 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -104,6 +104,7 @@
 #define VTCR_EL2_RES1  (1 << 31)
 #define VTCR_EL2_HD(1 << 22)
 #define VTCR_EL2_HA(1 << 21)
+#define VTCR_EL2_PS_SHIFT  TCR_EL2_PS_SHIFT
 #define VTCR_EL2_PS_MASK   TCR_EL2_PS_MASK
 #define VTCR_EL2_TG0_MASK  TCR_TG0_MASK
 #define VTCR_EL2_TG0_4KTCR_TG0_4K
@@ -177,6 +178,8 @@
 #define VTTBR_VMID_SHIFT  (UL(48))
 #define VTTBR_VMID_MASK(size) (_AT(u64, (1 << size) - 1) << VTTBR_VMID_SHIFT)
 
+#define SCTLR_EE   (UL(1) << 25)
+
 /* Hyp System Trap Register */
 #define HSTR_EL2_T(x)  (1 << x)
 
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 7fc7a83..c4efcd5 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -322,9 +322,21 @@ static inline unsigned int kvm_get_vmid_bits(void)
return (cpuid_feature_extract_unsigned_field(reg, 
ID_AA64MMFR1_VMIDBITS_SHIFT) == 2) ? 16 : 8;
 }
 
+struct kvm_s2_trans {
+   phys_addr_t output;
+   phys_addr_t block_size;
+   bool writable;
+   bool readable;
+   int level;
+   u32 esr;
+   u64 upper_attr;
+};
+
 struct kvm_nested_s2_mmu *get_nested_mmu(struct kvm_vcpu *vcpu, u64 vttbr);
 struct kvm_s2_mmu *vcpu_get_active_s2_mmu(struct kvm_vcpu *vcpu);
 void update_nested_s2_mmu(struct kvm_vcpu *vcpu);
+int kvm_walk_nested_s2(struct kvm_vcpu *vcpu, phys_addr_t gipa,
+  struct kvm_s2_trans *result);
 void kvm_nested_s2_unmap(struct kvm_vcpu *vcpu);
 void kvm_nested_s2_free(struct kvm *kvm);
 void kvm_nested_s2_wp(struct kvm *kvm);
diff --git a/arch/arm64/kvm/mmu-nested.c b/arch/arm64/kvm/mmu-nested.c
index 3ee20f2..fb694b7 100644
--- a/arch/arm64/kvm/mmu-nested.c
+++ b/arch/arm64/kvm/mmu-nested.c
@@ -22,6 +22,247 @@
 #include 
 #include 
 
+struct s2_walk_info {
+   unsigned int pgshift;
+   unsigned int pgsize;
+   unsigned int ps;
+   unsigned int sl;
+   unsigned int t0sz;
+};
+
+static unsigned int ps_to_output_size(unsigned int ps)
+{
+   switch (ps) {
+   case 0: return 32;
+   case 1: return 36;
+   case 2: return 40;
+   case 3: return 42;
+   case 4: return 44;
+   case 5:
+   default:
+   return 48;
+   }
+}
+
+static unsigned int pa_max(void)
+{
+/* We always emulate a VM with maximum PA size of KVM_PHYS_SIZE. */
+   return KVM_PHYS_SHIFT;
+}
+
+static int esr_s2_fault(struct kvm_vcpu *vcpu, int level, u

[RFC PATCH v2 09/31] KVM: arm/arm64: Manage mmus for nested VMs

2017-10-02 Thread Jintack Lim
Now that a hypervisor can run in the virtual EL2, the guest hypervisor
can assign any VMID to its own VMs. To avoid conflicts between VMIDs
among a host and guest(s), the host hypervisor maps each VMID from a
guest hypervisor's view (i.e. virtual VMID) to an unique shadow VMID.
It also manages a set of shadow stage-2 page tables for each shadow
VMID. All this information is stored in kvm_nested_s2_mmu struct.

A host hypervisor manages a list of kvm_nested_s2_mmu objects per VM. On
a VM entry it searches an object in the list using a virtual VMID as a
key.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---

Notes:
v1-->v2:
- This is a merged commit of [RFC 39/55] and [RFC 40/55].
- Updated the commit message and comments.
- Defer creating a new nested mmu structure until we enter the VM with 
stage 2
  paging enabled, which was previously done on vttbr_el2 write operations.
- Use the existing kvm->mmu_lock when iterating nested mmus instead of 
creating one.

 arch/arm/include/asm/kvm_host.h  |  12 
 arch/arm64/include/asm/kvm_emulate.h |  13 ++---
 arch/arm64/include/asm/kvm_host.h|  25 
 arch/arm64/include/asm/kvm_mmu.h |  21 +++
 arch/arm64/kvm/Makefile  |   1 +
 arch/arm64/kvm/context.c |   2 +-
 arch/arm64/kvm/mmu-nested.c  | 108 +++
 virt/kvm/arm/arm.c   |   1 +
 8 files changed, 174 insertions(+), 9 deletions(-)
 create mode 100644 arch/arm64/kvm/mmu-nested.c

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 33ccdbe..d84c1c1 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -67,6 +67,15 @@ struct kvm_s2_mmu {
pgd_t *pgd;
 };
 
+/* Per shadow VMID mmu structure. This is only for nested virtualization */
+struct kvm_nested_s2_mmu {
+   struct kvm_s2_mmu mmu;
+
+   u64 virtual_vttbr;
+
+   struct list_head list;
+};
+
 struct kvm_arch {
/* Stage 2 paging state for the VM */
struct kvm_s2_mmu mmu;
@@ -79,6 +88,9 @@ struct kvm_arch {
 * here.
 */
 
+   /* Never used on arm but added to be compatible with arm64 */
+   struct list_head nested_mmu_list;
+
/* Interrupt controller */
struct vgic_distvgic;
int max_vcpus;
diff --git a/arch/arm64/include/asm/kvm_emulate.h 
b/arch/arm64/include/asm/kvm_emulate.h
index 71a3a04..f476576 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -199,6 +199,11 @@ static inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu)
return false;
 }
 
+static inline bool vcpu_nested_stage2_enabled(const struct kvm_vcpu *vcpu)
+{
+   return (vcpu_sys_reg(vcpu, HCR_EL2) & HCR_VM);
+}
+
 static inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu)
 {
return vcpu->arch.fault.esr_el2;
@@ -385,12 +390,4 @@ static inline unsigned long vcpu_data_host_to_guest(struct 
kvm_vcpu *vcpu,
return data;/* Leave LE untouched */
 }
 
-static inline struct kvm_s2_vmid *vcpu_get_active_vmid(struct kvm_vcpu *vcpu)
-{
-   if (unlikely(is_hyp_ctxt(vcpu)))
-   return >kvm->arch.mmu.el2_vmid;
-
-   return >kvm->arch.mmu.vmid;
-}
-
 #endif /* __ARM64_KVM_EMULATE_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h 
b/arch/arm64/include/asm/kvm_host.h
index a7edf0e..0c37e49 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -65,6 +65,28 @@ struct kvm_s2_mmu {
pgd_t *pgd;
 };
 
+/* Per shadow VMID mmu structure */
+struct kvm_nested_s2_mmu {
+   struct kvm_s2_mmu mmu;
+
+   /*
+* virtual_vttbr contains vttbr_el2 value from the guest hypervisor.
+* We use vmid field as a key to search for this mmu object in the list,
+* and ignore baddr field.
+*
+* Note that we may use both of vmid field and baddr field respectively
+* to find a shadow VMID and a pointer to the shadow stage-2 page
+* table, then combine them to set up hw_vttbr. The only benefit of
+* doing that would be reusing shadow stage-2 page tables for different
+* VMIDs, which is not usual. So, we choose the current design for the
+* simplicity.
+*
+*/
+   u64 virtual_vttbr;
+
+   struct list_head list;
+};
+
 struct kvm_arch {
/* Stage 2 paging state for the VM */
struct kvm_s2_mmu mmu;
@@ -77,6 +99,9 @@ struct kvm_arch {
 
/* Interrupt controller */
struct vgic_distvgic;
+
+   /* Stage 2 shadow paging contexts for nested L2 VM */
+   struct list_head nested_mmu_list;
 };
 
 #define KVM_NR_MEM_OBJS 40
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index bceaec1..452912f 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -112,6 +112,7 @@

[RFC PATCH v2 08/31] KVM: arm/arm64: Make mmu functions non-static

2017-10-02 Thread Jintack Lim
From: Christoffer Dall <christoffer.d...@linaro.org>

Make mmu functions non-static so that we can reuse those functions
to support mmu for the nested VMs.

Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_mmu.h |  9 
 virt/kvm/arm/mmu.c   | 94 +++-
 2 files changed, 64 insertions(+), 39 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 21c0299..bceaec1 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -145,9 +145,18 @@ static inline unsigned long __kern_hyp_va(unsigned long v)
 
 void stage2_unmap_vm(struct kvm *kvm);
 int kvm_alloc_stage2_pgd(struct kvm *kvm);
+int __kvm_alloc_stage2_pgd(struct kvm_s2_mmu *mmu);
 void kvm_free_stage2_pgd(struct kvm *kvm);
+void __kvm_free_stage2_pgd(struct kvm *kvm, struct kvm_s2_mmu *mmu);
 int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
  phys_addr_t pa, unsigned long size, bool writable);
+void kvm_unmap_stage2_range(struct kvm *kvm, struct kvm_s2_mmu *mmu,
+   phys_addr_t start, u64 size);
+void kvm_stage2_wp_range(struct kvm *kvm, struct kvm_s2_mmu *mmu,
+phys_addr_t addr, phys_addr_t end);
+void kvm_stage2_flush_range(struct kvm_s2_mmu *mmu,
+   phys_addr_t start, phys_addr_t end);
+
 
 int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run);
 
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index 184cdc9..ca10799 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -307,7 +307,7 @@ static void unmap_stage2_puds(struct kvm_s2_mmu *mmu, pgd_t 
*pgd,
 }
 
 /**
- * unmap_stage2_range -- Clear stage2 page table entries to unmap a range
+ * kvm_unmap_stage2_range -- Clear stage2 page table entries to unmap a range
  * @kvm:   The VM pointer
  * @start: The intermediate physical base address of the range to unmap
  * @size:  The size of the area to unmap
@@ -317,12 +317,12 @@ static void unmap_stage2_puds(struct kvm_s2_mmu *mmu, 
pgd_t *pgd,
  * destroying the VM), otherwise another faulting VCPU may come in and mess
  * with things behind our backs.
  */
-static void unmap_stage2_range(struct kvm *kvm, phys_addr_t start, u64 size)
+void kvm_unmap_stage2_range(struct kvm *kvm, struct kvm_s2_mmu *mmu,
+   phys_addr_t start, u64 size)
 {
pgd_t *pgd;
phys_addr_t addr = start, end = start + size;
phys_addr_t next;
-   struct kvm_s2_mmu *mmu = >arch.mmu;
 
assert_spin_locked(>mmu_lock);
pgd = mmu->pgd + stage2_pgd_index(addr);
@@ -391,11 +391,10 @@ static void stage2_flush_puds(pgd_t *pgd, phys_addr_t 
addr, phys_addr_t end)
} while (pud++, addr = next, addr != end);
 }
 
-static void stage2_flush_memslot(struct kvm_s2_mmu *mmu,
-struct kvm_memory_slot *memslot)
+void kvm_stage2_flush_range(struct kvm_s2_mmu *mmu,
+   phys_addr_t start, phys_addr_t end)
 {
-   phys_addr_t addr = memslot->base_gfn << PAGE_SHIFT;
-   phys_addr_t end = addr + PAGE_SIZE * memslot->npages;
+   phys_addr_t addr = start;
phys_addr_t next;
pgd_t *pgd;
 
@@ -406,6 +405,15 @@ static void stage2_flush_memslot(struct kvm_s2_mmu *mmu,
} while (pgd++, addr = next, addr != end);
 }
 
+static void stage2_flush_memslot(struct kvm_s2_mmu *mmu,
+   struct kvm_memory_slot *memslot)
+{
+   phys_addr_t start = memslot->base_gfn << PAGE_SHIFT;
+   phys_addr_t end = start + PAGE_SIZE * memslot->npages;
+
+   kvm_stage2_flush_range(mmu, start, end);
+}
+
 /**
  * stage2_flush_vm - Invalidate cache for pages mapped in stage 2
  * @kvm: The struct kvm pointer
@@ -762,21 +770,9 @@ int create_hyp_io_mappings(void *from, void *to, 
phys_addr_t phys_addr)
 __phys_to_pfn(phys_addr), PAGE_HYP_DEVICE);
 }
 
-/**
- * kvm_alloc_stage2_pgd - allocate level-1 table for stage-2 translation.
- * @kvm:   The KVM struct pointer for the VM.
- *
- * Allocates only the stage-2 HW PGD level table(s) (can support either full
- * 40-bit input addresses or limited to 32-bit input addresses). Clears the
- * allocated pages.
- *
- * Note we don't need locking here as this is only called when the VM is
- * created, which can only be done once.
- */
-int kvm_alloc_stage2_pgd(struct kvm *kvm)
+int __kvm_alloc_stage2_pgd(struct kvm_s2_mmu *mmu)
 {
pgd_t *pgd;
-   struct kvm_s2_mmu *mmu = >arch.mmu;
 
if (mmu->pgd != NULL) {
kvm_err("kvm_arch already initialized?\n");
@@ -793,6 +789,22 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm)
return 0;
 }
 
+/**
+ * kvm_alloc_stage2_pgd - allocate level-1 table for stage-2 translation.
+ * @k

[RFC PATCH v2 10/31] KVM: arm/arm64: Unmap/flush shadow stage 2 page tables

2017-10-02 Thread Jintack Lim
From: Christoffer Dall <christoffer.d...@linaro.org>

Unmap/flush shadow stage 2 page tables for the nested VMs as well as the
stage 2 page table for the guest hypervisor.

Note: A bunch of the code in mmu.c relating to MMU notifiers is
currently dealt with in an extremely abrupt way, for example by clearing
out an entire shadow stage-2 table. This will be handled in a more
efficient way using the reverse mapping feature in a later version of
the patch series.

Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Jintack Lim <jintack@linaro.org>
---

Notes:
v1-->v2:
- Removed an unnecessary iteration for each vcpu in 
kvm_nested_s2_all_vcpus_*()
  functions and remove all_vcpus in the function names; a list of nested mmu
  is per VM, not per vcpu.
- Renamed kvm_nested_s2_unmap() to kvm_nested_s2_clear()
- Renamed kvm_nested_s2_teardown() to kvm_nested_s2_free()
- Removed the unused kvm_nested_s2_init() function.

 arch/arm/include/asm/kvm_mmu.h   |  6 ++
 arch/arm64/include/asm/kvm_mmu.h |  5 +
 arch/arm64/kvm/mmu-nested.c  | 40 
 virt/kvm/arm/arm.c   |  6 +-
 virt/kvm/arm/mmu.c   | 17 +
 5 files changed, 73 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 86fdc70..d3eafc5 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -221,6 +221,12 @@ static inline unsigned int kvm_get_vmid_bits(void)
return 8;
 }
 
+static inline void kvm_nested_s2_unmap(struct kvm_vcpu *vcpu) { }
+static inline void kvm_nested_s2_free(struct kvm *kvm) { }
+static inline void kvm_nested_s2_wp(struct kvm *kvm) { }
+static inline void kvm_nested_s2_clear(struct kvm *kvm) { }
+static inline void kvm_nested_s2_flush(struct kvm *kvm) { }
+
 static inline u64 kvm_get_vttbr(struct kvm_s2_vmid *vmid,
struct kvm_s2_mmu *mmu)
 {
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 452912f..7fc7a83 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -325,6 +325,11 @@ static inline unsigned int kvm_get_vmid_bits(void)
 struct kvm_nested_s2_mmu *get_nested_mmu(struct kvm_vcpu *vcpu, u64 vttbr);
 struct kvm_s2_mmu *vcpu_get_active_s2_mmu(struct kvm_vcpu *vcpu);
 void update_nested_s2_mmu(struct kvm_vcpu *vcpu);
+void kvm_nested_s2_unmap(struct kvm_vcpu *vcpu);
+void kvm_nested_s2_free(struct kvm *kvm);
+void kvm_nested_s2_wp(struct kvm *kvm);
+void kvm_nested_s2_clear(struct kvm *kvm);
+void kvm_nested_s2_flush(struct kvm *kvm);
 
 static inline u64 kvm_get_vttbr(struct kvm_s2_vmid *vmid,
struct kvm_s2_mmu *mmu)
diff --git a/arch/arm64/kvm/mmu-nested.c b/arch/arm64/kvm/mmu-nested.c
index c436daf..3ee20f2 100644
--- a/arch/arm64/kvm/mmu-nested.c
+++ b/arch/arm64/kvm/mmu-nested.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2017 - Columbia University and Linaro Ltd.
  * Author: Jintack Lim <jintack@linaro.org>
+ * Author: Christoffer Dall <cd...@cs.columbia.edu>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -21,6 +22,45 @@
 #include 
 #include 
 
+/* expects kvm->mmu_lock to be held */
+void kvm_nested_s2_wp(struct kvm *kvm)
+{
+   struct kvm_nested_s2_mmu *nested_mmu;
+   struct list_head *nested_mmu_list = >arch.nested_mmu_list;
+
+   list_for_each_entry_rcu(nested_mmu, nested_mmu_list, list)
+   kvm_stage2_wp_range(kvm, _mmu->mmu, 0, KVM_PHYS_SIZE);
+}
+
+/* expects kvm->mmu_lock to be held */
+void kvm_nested_s2_clear(struct kvm *kvm)
+{
+   struct kvm_nested_s2_mmu *nested_mmu;
+   struct list_head *nested_mmu_list = >arch.nested_mmu_list;
+
+   list_for_each_entry_rcu(nested_mmu, nested_mmu_list, list)
+   kvm_unmap_stage2_range(kvm, _mmu->mmu, 0, KVM_PHYS_SIZE);
+}
+
+/* expects kvm->mmu_lock to be held */
+void kvm_nested_s2_flush(struct kvm *kvm)
+{
+   struct kvm_nested_s2_mmu *nested_mmu;
+   struct list_head *nested_mmu_list = >arch.nested_mmu_list;
+
+   list_for_each_entry_rcu(nested_mmu, nested_mmu_list, list)
+   kvm_stage2_flush_range(_mmu->mmu, 0, KVM_PHYS_SIZE);
+}
+
+void kvm_nested_s2_free(struct kvm *kvm)
+{
+   struct kvm_nested_s2_mmu *nested_mmu;
+   struct list_head *nested_mmu_list = >arch.nested_mmu_list;
+
+   list_for_each_entry_rcu(nested_mmu, nested_mmu_list, list)
+   __kvm_free_stage2_pgd(kvm, _mmu->mmu);
+}
+
 static struct kvm_nested_s2_mmu *lookup_nested_mmu(struct kvm_vcpu *vcpu,
   u64 vttbr)
 {
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 4548d77..08706f8 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/

[RFC PATCH v2 03/31] KVM: arm/arm64: Remove unused params in mmu functions

2017-10-02 Thread Jintack Lim
From: Christoffer Dall <christoffer.d...@linaro.org>

stage2_flush_xxx functions take a pointer to the kvm struct as the first
parameter but they are never used. Clean this up before modifying mmu
code for nested virtualization support.

Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 virt/kvm/arm/mmu.c | 15 ++-
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index f2d5b6c..0a5f5ca 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -315,8 +315,7 @@ static void unmap_stage2_range(struct kvm *kvm, phys_addr_t 
start, u64 size)
} while (pgd++, addr = next, addr != end);
 }
 
-static void stage2_flush_ptes(struct kvm *kvm, pmd_t *pmd,
- phys_addr_t addr, phys_addr_t end)
+static void stage2_flush_ptes(pmd_t *pmd, phys_addr_t addr, phys_addr_t end)
 {
pte_t *pte;
 
@@ -327,8 +326,7 @@ static void stage2_flush_ptes(struct kvm *kvm, pmd_t *pmd,
} while (pte++, addr += PAGE_SIZE, addr != end);
 }
 
-static void stage2_flush_pmds(struct kvm *kvm, pud_t *pud,
- phys_addr_t addr, phys_addr_t end)
+static void stage2_flush_pmds(pud_t *pud, phys_addr_t addr, phys_addr_t end)
 {
pmd_t *pmd;
phys_addr_t next;
@@ -340,13 +338,12 @@ static void stage2_flush_pmds(struct kvm *kvm, pud_t *pud,
if (pmd_thp_or_huge(*pmd))
kvm_flush_dcache_pmd(*pmd);
else
-   stage2_flush_ptes(kvm, pmd, addr, next);
+   stage2_flush_ptes(pmd, addr, next);
}
} while (pmd++, addr = next, addr != end);
 }
 
-static void stage2_flush_puds(struct kvm *kvm, pgd_t *pgd,
- phys_addr_t addr, phys_addr_t end)
+static void stage2_flush_puds(pgd_t *pgd, phys_addr_t addr, phys_addr_t end)
 {
pud_t *pud;
phys_addr_t next;
@@ -358,7 +355,7 @@ static void stage2_flush_puds(struct kvm *kvm, pgd_t *pgd,
if (stage2_pud_huge(*pud))
kvm_flush_dcache_pud(*pud);
else
-   stage2_flush_pmds(kvm, pud, addr, next);
+   stage2_flush_pmds(pud, addr, next);
}
} while (pud++, addr = next, addr != end);
 }
@@ -374,7 +371,7 @@ static void stage2_flush_memslot(struct kvm *kvm,
pgd = kvm->arch.pgd + stage2_pgd_index(addr);
do {
next = stage2_pgd_addr_end(addr, end);
-   stage2_flush_puds(kvm, pgd, addr, next);
+   stage2_flush_puds(pgd, addr, next);
} while (pgd++, addr = next, addr != end);
 }
 
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 07/31] KVM: arm64: Setup vttbr_el2 on each VM entry

2017-10-02 Thread Jintack Lim
From: Christoffer Dall <christoffer.d...@linaro.org>

Now that the vttbr value will be different depending on the VM's
exception level, we set it on each VM entry.

We only have one mmu instance at this point, but there will be
multiple of them if we come to run nested VMs.

Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>
---
 arch/arm64/kvm/context.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/kvm/context.c b/arch/arm64/kvm/context.c
index a7811e1..afd1702 100644
--- a/arch/arm64/kvm/context.c
+++ b/arch/arm64/kvm/context.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 
 struct el1_el2_map {
enum vcpu_sysregel1;
@@ -174,6 +175,15 @@ static void flush_shadow_el1_sysregs(struct kvm_vcpu *vcpu)
flush_shadow_el1_sysregs_nvhe(vcpu);
 }
 
+static void setup_s2_mmu(struct kvm_vcpu *vcpu)
+{
+   struct kvm_s2_mmu *mmu = >kvm->arch.mmu;
+   struct kvm_s2_vmid *vmid = vcpu_get_active_vmid(vcpu);
+
+   vcpu->arch.hw_vttbr = kvm_get_vttbr(vmid, mmu);
+   vcpu->arch.hw_mmu = mmu;
+}
+
 /*
  * List of EL0 and EL1 registers which we allow the virtual EL2 mode to access
  * directly without trapping. This is possible because the impact of
@@ -323,6 +333,8 @@ void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu)
setup_mpidr_el1(vcpu);
ctxt->hw_sys_regs = ctxt->sys_regs;
}
+
+   setup_s2_mmu(vcpu);
 }
 
 /**
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 06/31] KVM: arm64: Invalidate virtual EL2 TLB entries when needed

2017-10-02 Thread Jintack Lim
From: Christoffer Dall <christoffer.d...@linaro.org>

Sometimes when we are invalidating the TLB for a certain S2 MMU
context, this context can also have EL2 context associated with it and
we have to invalidate this too.

Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 virt/kvm/arm/arm.c |  5 +
 virt/kvm/arm/mmu.c | 23 ++-
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 41e0654..63dd897 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -362,6 +362,11 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
u64 vttbr = kvm_get_vttbr(>vmid, mmu);
 
kvm_call_hyp(__kvm_tlb_flush_local_vmid, vttbr);
+
+   if (mmu->el2_vmid.vmid) {
+   vttbr = kvm_get_vttbr(>el2_vmid, mmu);
+   kvm_call_hyp(__kvm_tlb_flush_local_vmid, vttbr);
+   }
*last_ran = vcpu->vcpu_id;
}
 
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index 0edcf23..184cdc9 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -64,7 +64,21 @@ void kvm_flush_remote_tlbs(struct kvm *kvm)
struct kvm_s2_mmu *mmu = >arch.mmu;
u64 vttbr = kvm_get_vttbr(>vmid, mmu);
 
-   kvm_call_hyp(__kvm_tlb_flush_vmid, vttbr);
+   if (!mmu->el2_vmid.vmid) {
+   /*
+* For a normal (i.e. non-nested) guest, flush entries for the
+* given VMID *
+*/
+   kvm_call_hyp(__kvm_tlb_flush_vmid, vttbr);
+   } else {
+   /*
+* When supporting nested virtualization, we can have multiple
+* VMIDs in play for each VCPU in the VM, so it's really not
+* worth it to try to quiesce the system and flush all the
+* VMIDs that may be in use, instead just nuke the whole thing.
+*/
+   kvm_call_hyp(__kvm_flush_vm_context);
+   }
 }
 
 static void kvm_tlb_flush_vmid_ipa(struct kvm_s2_mmu *mmu, phys_addr_t ipa)
@@ -72,6 +86,13 @@ static void kvm_tlb_flush_vmid_ipa(struct kvm_s2_mmu *mmu, 
phys_addr_t ipa)
u64 vttbr = kvm_get_vttbr(>vmid, mmu);
 
kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, vttbr, ipa);
+
+   if (!mmu->el2_vmid.vmid) {
+   /* Nothing to do more for a non-nested guest */
+   return;
+   }
+   vttbr = kvm_get_vttbr(>el2_vmid, mmu);
+   kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, vttbr, ipa);
 }
 
 /*
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 00/31] Nested Virtualization on KVM/ARM - memory virtualization

2017-10-02 Thread Jintack Lim
This is the second part of nested virtualization patch series v2 - memory
virtualization. You can find the first part (cpu virtualization) here [1].

For memory virtualization, the biggest issue is that we now have more than two
stages of translation when running nested VMs while hardware only supports two
stages. We choose to merge two stage-2 page tables (one from the guest
hypervisor and the other from the host hypervisor) and create shadow stage-2
page tables, which have mappings from the nested VM’s physical addresses to the
machine physical addresses. Stage-1 translation is done by the hardware as is
done for the normal VMs. Patch 2 to 14 handle the shadow page table. Note that
patch 1 is borrowed from Dave Martin's SVE patches [2], so that we can fake
ID_AA64MMFR0_EL1 register value to the guest hypervisor in patch 2.

The second half of the patch series (15 to 30) are to handle AT and TLBI
instructions from the guest hypervisor. To get an idea of the AT instruction
emulation, I'd recommend you start with patch 19. For TLBI instructions, see
individual patches from patch 24 to 30. Note that we need to forward AT and
TLBI instructions to the virtual EL2 if corresponding bits are set in the
virtual HCR_EL2. This is mostly for recursive virtualization, and handled in
patch 29 and 30.

This patch set is tested on the FastModel with the v8.3 extension for arm64. I
used a cubietruck for arm32 and was able to boot a VM without a problem. See
the test setup here [3, 4].

This patch series is based on kvm/next d38338e and cpu virtualization patch set
[1].  The whole patch series including cpu, memory, VGIC, and timer patches is
available here:

g...@github.com:columbia/nesting-pub.git rfc-v2-mem

TODO:
- Implement the reverse mapping feature to handle mmu notifiers more
  efficiently.

v1-->v2:
- Fixed a bug on arm32 (patch 5).
- Removed most of TODOs.
- Updated comments and commit messages.
- Put change notes for each patches if any.

[1] https://lists.cs.columbia.edu/pipermail/kvmarm/2017-July/026388.html
[2] https://lists.cs.columbia.edu/pipermail/kvmarm/2017-August/026961.html
[3] https://lists.cs.columbia.edu/pipermail/kvmarm/2017-July/026427.html
[4] 
https://github.com/columbia/nesting-pub/wiki/Nested-virtualization-on-ARM-setup

Christoffer Dall (12):
  KVM: arm/arm64: Remove unused params in mmu functions
  KVM: arm/arm64: Abstract stage-2 MMU state into a separate structure
  KVM: arm/arm64: Support mmu for the virtual EL2 execution
  KVM: arm64: Invalidate virtual EL2 TLB entries when needed
  KVM: arm64: Setup vttbr_el2 on each VM entry
  KVM: arm/arm64: Make mmu functions non-static
  KVM: arm/arm64: Unmap/flush shadow stage 2 page tables
  KVM: arm64: Implement nested Stage-2 page table walk logic
  KVM: arm/arm64: Handle shadow stage 2 page faults
  KVM: arm/arm64: Move kvm_is_write_fault to header file
  KVM: arm/arm64: Forward the guest hypervisor's stage 2 permission
faults
  KVM: arm64: Fixes to toggle_cache for nesting

Dave Martin (1):
  arm64: KVM: Hide unsupported AArch64 CPU features from guests

Jintack Lim (18):
  KVM: arm64: Expose limited memory management support to the virtual
EL2
  KVM: arm/arm64: Manage mmus for nested VMs
  KVM: arm64: Move system register helper functions around
  KVM: arm64: Introduce sys_reg_desc.forward_trap
  KVM: arm64: Rework the system instruction emulation framework
  KVM: arm64: Enumerate AT and TLBI instructions to emulate
  KVM: arm64: Describe AT instruction emulation design
  KVM: arm64: Implement AT instruction handling
  KVM: arm64: Emulate AT S1E[01] instructions
  KVM: arm64: Emulate AT S1E2 instructions
  KVM: arm64: Emulate AT S12E[01] instructions
  KVM: arm64: Emulate TLBI ALLE2(IS) instruction
  KVM: arm64: Emulate TLBI VAE2* instrutions
  KVM: arm64: Emulate TLBI ALLE1(IS)
  KVM: arm64: Emulate TLBI VMALLS12E1(IS) instruction
  KVM: arm64: Emulate TLBI IPAS2E1* instructions
  KVM: arm64: Respect the virtual HCR_EL2.AT and NV setting
  KVM: arm64: Emulate TLBI instructions accesible from EL1

 arch/arm/include/asm/kvm_asm.h   |   7 +-
 arch/arm/include/asm/kvm_emulate.h   |  19 +
 arch/arm/include/asm/kvm_host.h  |  42 +-
 arch/arm/include/asm/kvm_mmu.h   |  44 ++
 arch/arm/kvm/hyp/switch.c|   3 +-
 arch/arm/kvm/hyp/tlb.c   |  15 +-
 arch/arm64/include/asm/esr.h |   1 +
 arch/arm64/include/asm/kvm_arm.h |   5 +
 arch/arm64/include/asm/kvm_asm.h |  12 +-
 arch/arm64/include/asm/kvm_emulate.h |  29 ++
 arch/arm64/include/asm/kvm_host.h|  45 +-
 arch/arm64/include/asm/kvm_mmu.h |  69 ++-
 arch/arm64/include/asm/sysreg.h  |  56 +++
 arch/arm64/kvm/Makefile  |   1 +
 arch/arm64/kvm/context.c |  12 +
 arch/arm64/kvm/hyp/Makefile  |   1 +
 arch/arm64/kvm/hyp/at.c  | 131 +
 arch/arm64/kvm/hyp/switch.c  |   8 +-
 arch/arm64/kvm/hyp/tlb.c | 114 -
 arch/arm64/kvm/mmu-nested.c  | 

[RFC PATCH v2 02/31] KVM: arm64: Expose limited memory management support to the virtual EL2

2017-10-02 Thread Jintack Lim
Exposing memory management support to the virtual EL2 as is exposed to
the host hypervisor would make the implementation too complex and
inefficient. Therefore expose limited memory management support for the
following two cases.

We expose same or larger page granules than the one host uses.  We can
theoretically support a guest hypervisor having smaller-than-host
granularities but it is not worth it since it makes the implementation
complicated and it would waste memory.

We expose 40 bits of physical address range to the virtual EL2, because
we only support a 40bit IPA for the guest.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 47 ++-
 1 file changed, 46 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 65f4c20..395b964 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1233,6 +1233,50 @@ static int set_raz_id_reg(struct kvm_vcpu *vcpu, const 
struct sys_reg_desc *rd,
.set_user = set_raz_id_reg, \
 }
 
+static bool access_id_aa64mmfr0_el1(struct kvm_vcpu *v,
+   struct sys_reg_params *p,
+   const struct sys_reg_desc *r)
+{
+   u64 val;
+   u64 vtcr_tg0 = VTCR_EL2_TGRAN_FLAGS & VTCR_EL2_TG0_MASK;
+
+   if (!nested_virt_in_use(v))
+   return access_id_reg(v, p, r);
+
+   if (p->is_write)
+   return write_to_read_only(v, p, r);
+
+   val = p->regval;
+   /*
+* Don't expose granules smaller than the host's granule to the guest.
+* We can theoretically support a guest hypervisor having
+* smaller-than-host granularities but it is not worth it since it
+* makes the implementation complicated and it would waste memory.
+*/
+   switch (vtcr_tg0) {
+   case VTCR_EL2_TG0_64K:
+   /* 16KB granule not supported */
+   val &= ~(0xf << ID_AA64MMFR0_TGRAN16_SHIFT);
+   val |= (ID_AA64MMFR0_TGRAN16_NI << ID_AA64MMFR0_TGRAN16_SHIFT);
+   /* fall through */
+   case VTCR_EL2_TG0_16K:
+   /* 4KB granule not supported */
+   val &= ~(0xf << ID_AA64MMFR0_TGRAN4_SHIFT);
+   val |= (ID_AA64MMFR0_TGRAN4_NI << ID_AA64MMFR0_TGRAN4_SHIFT);
+   break;
+   default:
+   break;
+   }
+
+   /* Expose only 40 bits physical address range to the guest hypervisor */
+   val &= ~(0xf << ID_AA64MMFR0_PARANGE_SHIFT);
+   val |= (0x2 << ID_AA64MMFR0_PARANGE_SHIFT); /* 40 bits */
+
+   p->regval = val;
+
+   return true;
+}
+
 /*
  * sys_reg_desc initialiser for known ID registers that we hide from guests.
  * For now, these are exposed just like unallocated ID regs: they appear
@@ -1309,7 +1353,8 @@ static int set_raz_id_reg(struct kvm_vcpu *vcpu, const 
struct sys_reg_desc *rd,
ID_SANITISED(ID_PFR1_EL1),
ID_SANITISED(ID_DFR0_EL1),
ID_HIDDEN(ID_AFR0_EL1),
-   ID_SANITISED(ID_MMFR0_EL1),
+   { SYS_DESC(SYS_ID_MMFR0_EL1), access_id_aa64mmfr0_el1, NULL, 0, 0,
+ get_id_reg, set_id_reg },
ID_SANITISED(ID_MMFR1_EL1),
ID_SANITISED(ID_MMFR2_EL1),
ID_SANITISED(ID_MMFR3_EL1),
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 01/31] arm64: KVM: Hide unsupported AArch64 CPU features from guests

2017-10-02 Thread Jintack Lim
From: Dave Martin 

Currently, a guest kernel sees the true CPU feature registers
(ID_*_EL1) when it reads them using MRS instructions.  This means
that the guest will observe features that are present in the
hardware but the host doesn't understand or doesn't provide support
for.  A guest may legimitately try to use such a feature as per the
architecture, but use of the feature may trap instead of working
normally, triggering undef injection into the guest.

This is not a problem for the host, but the guest may go wrong when
running on newer hardware than the host knows about.

This patch hides from guest VMs any AArch64-specific CPU features
that the host doesn't support, by exposing to the guest the
sanitised versions of the registers computed by the cpufeatures
framework, instead of the true hardware registers.  To achieve
this, HCR_EL2.TID3 is now set for AArch64 guests, and emulation
code is added to KVM to report the sanitised versions of the
affected registers in response to MRS and register reads from
userspace.

The affected registers are removed from invariant_sys_regs[] (since
the invariant_sys_regs handling is no longer quite correct for
them) and added to sys_reg_desgs[], with appropriate access(),
get_user() and set_user() methods.  No runtime vcpu storage is
allocated for the registers: instead, they are read on demand from
the cpufeatures framework.  This may need modification in the
future if there is a need for userspace to customise the features
visible to the guest.

Attempts by userspace to write the registers are handled similarly
to the current invariant_sys_regs handling: writes are permitted,
but only if they don't attempt to change the value.  This is
sufficient to support VM snapshot/restore from userspace.

Because of the additional registers, restoring a VM on an older
kernel may not work unless userspace knows how to handle the extra
VM registers exposed to the KVM user ABI by this patch.

Under the principle of least damage, this patch makes no attempt to
handle any of the other registers currently in
invariant_sys_regs[], or to emulate registers for AArch32: however,
these could be handled in a similar way in future, as necessary.

Signed-off-by: Dave Martin 
Cc: Marc Zyngier 

---

Changes since v1


Requested by Marc Zyngier:

* Get rid of ternary operator use in walk_sys_regs().

* Call write_to_read_only() if an attempt to write an ID reg is
trapped, rather than reinventing.
Probably we won't get there anyway: the architecture says that this
should undef at EL1 instead.

* Make ID register sysreg table less cryptic and spread the entries one
per line.
Also, make the architecturally unallocated and allocated but hidden
cases more clearly distinct.  These require the same behaviour but for
different reasons, so it's better to identify them as separate.

Other:

* Delete BUG_ON()s that are skipped by construction:
These check that the result of sys_reg_to_index() is a 64-bit
register, which is always true because sys_reg_to_index()
explicitly sets this.

* Remove duplicate const in __access_id_reg args [sparse]
---
 arch/arm64/include/asm/sysreg.h |   3 +
 arch/arm64/kvm/hyp/switch.c |   5 +
 arch/arm64/kvm/sys_regs.c   | 282 +---
 3 files changed, 245 insertions(+), 45 deletions(-)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index b8d4d0c..a051d42 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -149,6 +149,9 @@
 #define SYS_ID_AA64DFR0_EL1sys_reg(3, 0, 0, 5, 0)
 #define SYS_ID_AA64DFR1_EL1sys_reg(3, 0, 0, 5, 1)
 
+#define SYS_ID_AA64AFR0_EL1sys_reg(3, 0, 0, 5, 4)
+#define SYS_ID_AA64AFR1_EL1sys_reg(3, 0, 0, 5, 5)
+
 #define SYS_ID_AA64ISAR0_EL1   sys_reg(3, 0, 0, 6, 0)
 #define SYS_ID_AA64ISAR1_EL1   sys_reg(3, 0, 0, 6, 1)
 
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 50c90f2..2a64a5c 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -88,11 +88,15 @@ static void __hyp_text __activate_traps(struct kvm_vcpu 
*vcpu)
 * it will cause an exception.
 */
val = vcpu->arch.hcr_el2;
+
if (!(val & HCR_RW) && system_supports_fpsimd()) {
write_sysreg(1 << 30, fpexc32_el2);
isb();
}
 
+   if (val & HCR_RW) /* for AArch64 only: */
+   val |= HCR_TID3; /* TID3: trap feature register accesses */
+
if (is_hyp_ctxt(vcpu)) {
/*
 * For a guest hypervisor on v8.0, trap and emulate the EL1
@@ -113,6 +117,7 @@ static void __hyp_text __activate_traps(struct kvm_vcpu 
*vcpu)
}
 
write_sysreg(val, hcr_el2);
+
/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
write_sysreg(1 << 15, hstr_el2);
/*
diff --git 

Re: [RFC PATCH v2 20/38] KVM: arm64: Handle eret instruction traps

2017-08-01 Thread Jintack Lim
On Sun, Jul 30, 2017 at 4:00 PM, Christoffer Dall <cd...@linaro.org> wrote:
> On Tue, Jul 18, 2017 at 11:58:46AM -0500, Jintack Lim wrote:
>> When HCR.NV bit is set, eret instructions trap to EL2 with EC code 0x1A.
>> Emulate eret instructions by setting pc and pstate.
>
> It may be worth noting in the commit message that this is all we have to
> do, because the rest of the logic will then discover that the mode could
> change from virtual EL2 to EL1 and will setup the hw registers etc. when
> changing modes.

Makes sense. I'll write it up in the commit message.

>
>>
>> Note that the current exception level is always the virtual EL2, since
>> we set HCR_EL2.NV bit only when entering the virtual EL2. So, we take
>> spsr and elr states from the virtual _EL2 registers.
>>
>> Signed-off-by: Jintack Lim <jintack@linaro.org>
>> ---
>>  arch/arm64/include/asm/esr.h |  1 +
>>  arch/arm64/kvm/handle_exit.c | 16 
>>  arch/arm64/kvm/trace.h   | 21 +
>>  3 files changed, 38 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
>> index e7d8e28..210fde6 100644
>> --- a/arch/arm64/include/asm/esr.h
>> +++ b/arch/arm64/include/asm/esr.h
>> @@ -43,6 +43,7 @@
>>  #define ESR_ELx_EC_HVC64 (0x16)
>>  #define ESR_ELx_EC_SMC64 (0x17)
>>  #define ESR_ELx_EC_SYS64 (0x18)
>> +#define ESR_ELx_EC_ERET  (0x1A)
>>  /* Unallocated EC: 0x19 - 0x1E */
>>  #define ESR_ELx_EC_IMP_DEF   (0x1f)
>>  #define ESR_ELx_EC_IABT_LOW  (0x20)
>> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
>> index 17d8a16..9259881 100644
>> --- a/arch/arm64/kvm/handle_exit.c
>> +++ b/arch/arm64/kvm/handle_exit.c
>> @@ -147,6 +147,21 @@ static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu, 
>> struct kvm_run *run)
>>   return 1;
>>  }
>>
>> +static int kvm_handle_eret(struct kvm_vcpu *vcpu, struct kvm_run *run)
>> +{
>> + trace_kvm_nested_eret(vcpu, vcpu_el2_sreg(vcpu, ELR_EL2),
>> +   vcpu_el2_sreg(vcpu, SPSR_EL2));
>> +
>> + /*
>> +  * Note that the current exception level is always the virtual EL2,
>> +  * since we set HCR_EL2.NV bit only when entering the virtual EL2.
>> +  */
>> + *vcpu_pc(vcpu) = vcpu_el2_sreg(vcpu, ELR_EL2);
>> + *vcpu_cpsr(vcpu) = vcpu_el2_sreg(vcpu, SPSR_EL2);
>> +
>> + return 1;
>> +}
>> +
>>  static exit_handle_fn arm_exit_handlers[] = {
>>   [0 ... ESR_ELx_EC_MAX]  = kvm_handle_unknown_ec,
>>   [ESR_ELx_EC_WFx]= kvm_handle_wfx,
>> @@ -160,6 +175,7 @@ static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu, 
>> struct kvm_run *run)
>>   [ESR_ELx_EC_HVC64]  = handle_hvc,
>>   [ESR_ELx_EC_SMC64]  = handle_smc,
>>   [ESR_ELx_EC_SYS64]  = kvm_handle_sys_reg,
>> + [ESR_ELx_EC_ERET]   = kvm_handle_eret,
>>   [ESR_ELx_EC_IABT_LOW]   = kvm_handle_guest_abort,
>>   [ESR_ELx_EC_DABT_LOW]   = kvm_handle_guest_abort,
>>   [ESR_ELx_EC_SOFTSTP_LOW]= kvm_handle_guest_debug,
>> diff --git a/arch/arm64/kvm/trace.h b/arch/arm64/kvm/trace.h
>> index 7c86cfb..5f40987 100644
>> --- a/arch/arm64/kvm/trace.h
>> +++ b/arch/arm64/kvm/trace.h
>> @@ -187,6 +187,27 @@
>>   TP_printk("vcpu: %p, inject exception to vEL2: ESR_EL2 0x%lx, vector: 
>> 0x%016lx",
>> __entry->vcpu, __entry->esr_el2, __entry->pc)
>>  );
>> +
>> +TRACE_EVENT(kvm_nested_eret,
>> + TP_PROTO(struct kvm_vcpu *vcpu, unsigned long elr_el2,
>> +  unsigned long spsr_el2),
>> + TP_ARGS(vcpu, elr_el2, spsr_el2),
>> +
>> + TP_STRUCT__entry(
>> + __field(struct kvm_vcpu *,  vcpu)
>> + __field(unsigned long,  elr_el2)
>> + __field(unsigned long,  spsr_el2)
>> + ),
>> +
>> + TP_fast_assign(
>> + __entry->vcpu = vcpu;
>> + __entry->elr_el2 = elr_el2;
>> + __entry->spsr_el2 = spsr_el2;
>> + ),
>> +
>> + TP_printk("vcpu: %p, eret to elr_el2: 0x%016lx, with spsr_el2: 
>> 0x%08lx",
>> +   __entry->vcpu, __entry->elr_el2, __entry->spsr_el2)
>> +);
>>  #endif /* _TRACE_ARM64_KVM_H */
>>
>>  #undef TRACE_INCLUDE_PATH
>> --
>> 1.9.1
>>
>
> Otherwise this patch looks good.
>
> Thanks,
> -Christoffer
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [RFC PATCH v2 08/38] KVM: arm64: Add EL2 special registers to vcpu context

2017-08-01 Thread Jintack Lim
On Sun, Jul 30, 2017 at 3:59 PM, Christoffer Dall <cd...@linaro.org> wrote:
> On Tue, Jul 18, 2017 at 11:58:34AM -0500, Jintack Lim wrote:
>> To support the virtual EL2 execution, we need to maintain the EL2
>> special registers such as SPSR_EL2, ELR_EL2 and SP_EL2 in vcpu context.
>>
>> Note that SP_EL2 is not accessible in EL2, so we don't need a trap
>> handler for this register.
>
> Actually, it's not accessible *in the MRS/MSR instruction* but it is of
> course accessible as the current stack pointer (which is why you need
> the state, but not the trap handler).

That is correct. I'll fix the commit message.

>
> Otherwise, the patch looks good.

Thanks!

>
> Thanks,
> -Christoffer
>
>>
>> Signed-off-by: Jintack Lim <jintack@linaro.org>
>> ---
>>  arch/arm64/include/asm/kvm_host.h | 12 
>>  arch/arm64/include/asm/sysreg.h   |  4 
>>  arch/arm64/kvm/sys_regs.c | 38 
>> +-
>>  arch/arm64/kvm/sys_regs.h |  8 
>>  4 files changed, 57 insertions(+), 5 deletions(-)
>>
>> diff --git a/arch/arm64/include/asm/kvm_host.h 
>> b/arch/arm64/include/asm/kvm_host.h
>> index 1dc4ed6..57dccde 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -171,6 +171,15 @@ enum vcpu_sysreg {
>>   NR_SYS_REGS /* Nothing after this line! */
>>  };
>>
>> +enum el2_special_regs {
>> + __INVALID_EL2_SPECIAL_REG__,
>> + SPSR_EL2,   /* Saved Program Status Register (EL2) */
>> + ELR_EL2,/* Exception Link Register (EL2) */
>> + SP_EL2, /* Stack Pointer (EL2) */
>> +
>> + NR_EL2_SPECIAL_REGS
>> +};
>> +
>>  /* 32bit mapping */
>>  #define c0_MPIDR (MPIDR_EL1 * 2) /* MultiProcessor ID Register */
>>  #define c0_CSSELR(CSSELR_EL1 * 2)/* Cache Size Selection Register */
>> @@ -218,6 +227,8 @@ struct kvm_cpu_context {
>>   u64 sys_regs[NR_SYS_REGS];
>>   u32 copro[NR_COPRO_REGS];
>>   };
>> +
>> + u64 el2_special_regs[NR_EL2_SPECIAL_REGS];
>>  };
>>
>>  typedef struct kvm_cpu_context kvm_cpu_context_t;
>> @@ -307,6 +318,7 @@ struct kvm_vcpu_arch {
>>
>>  #define vcpu_gp_regs(v)  (&(v)->arch.ctxt.gp_regs)
>>  #define vcpu_sys_reg(v,r)((v)->arch.ctxt.sys_regs[(r)])
>> +#define vcpu_el2_sreg(v,r)   ((v)->arch.ctxt.el2_special_regs[(r)])
>>  /*
>>   * CP14 and CP15 live in the same array, as they are backed by the
>>   * same system registers.
>> diff --git a/arch/arm64/include/asm/sysreg.h 
>> b/arch/arm64/include/asm/sysreg.h
>> index 9277c4a..98c32ef 100644
>> --- a/arch/arm64/include/asm/sysreg.h
>> +++ b/arch/arm64/include/asm/sysreg.h
>> @@ -268,6 +268,8 @@
>>
>>  #define SYS_DACR32_EL2   sys_reg(3, 4, 3, 0, 0)
>>
>> +#define SYS_SPSR_EL2 sys_reg(3, 4, 4, 0, 0)
>> +#define SYS_ELR_EL2  sys_reg(3, 4, 4, 0, 1)
>>  #define SYS_SP_EL1   sys_reg(3, 4, 4, 1, 0)
>>
>>  #define SYS_IFSR32_EL2   sys_reg(3, 4, 5, 0, 1)
>> @@ -332,6 +334,8 @@
>>  #define SYS_CNTVOFF_EL2  sys_reg(3, 4, 14, 0, 3)
>>  #define SYS_CNTHCTL_EL2  sys_reg(3, 4, 14, 1, 0)
>>
>> +#define SYS_SP_EL2   sys_reg(3, 6, 4, 1, 0)
>> +
>>  /* Common SCTLR_ELx flags. */
>>  #define SCTLR_ELx_EE(1 << 25)
>>  #define SCTLR_ELx_I  (1 << 12)
>> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>> index 1568f8b..2b3ed70 100644
>> --- a/arch/arm64/kvm/sys_regs.c
>> +++ b/arch/arm64/kvm/sys_regs.c
>> @@ -900,15 +900,33 @@ static inline void access_rw(struct sys_reg_params *p, 
>> u64 *sysreg)
>>   *sysreg = p->regval;
>>  }
>>
>> +static u64 *get_special_reg(struct kvm_vcpu *vcpu, struct sys_reg_params *p)
>> +{
>> + u64 reg = sys_reg(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
>> +
>> + switch (reg) {
>> + case SYS_SP_EL1:
>> + return >arch.ctxt.gp_regs.sp_el1;
>> + case SYS_ELR_EL2:
>> + return _el2_sreg(vcpu, ELR_EL2);
>> + case SYS_SPSR_EL2:
>> + return _el2_sreg(vcpu, SPSR_EL2);
>> + default:
>> + return NULL;
>> + };
>> +}
>> +
>>  static bool trap_el2_regs(struct kvm_vcpu *vcpu,
>>

Re: [RFC PATCH v2 04/38] KVM: arm/arm64: Check if nested virtualization is in use

2017-08-01 Thread Jintack Lim
On Sun, Jul 30, 2017 at 3:59 PM, Christoffer Dall <cd...@linaro.org> wrote:
> On Tue, Jul 18, 2017 at 11:58:30AM -0500, Jintack Lim wrote:
>> Nested virtualizaion is in use only if all three conditions are met:
>> - The architecture supports nested virtualization.
>> - The kernel parameter is set.
>> - The userspace uses nested virtualiztion feature.
>>
>> Signed-off-by: Jintack Lim <jintack@linaro.org>
>> ---
>>  arch/arm/include/asm/kvm_host.h   | 11 +++
>>  arch/arm64/include/asm/kvm_host.h |  2 ++
>>  arch/arm64/kvm/nested.c   | 17 +
>>  virt/kvm/arm/arm.c|  4 
>>  4 files changed, 34 insertions(+)
>>
>> diff --git a/arch/arm/include/asm/kvm_host.h 
>> b/arch/arm/include/asm/kvm_host.h
>> index 00b0f97..7e9e6c8 100644
>> --- a/arch/arm/include/asm/kvm_host.h
>> +++ b/arch/arm/include/asm/kvm_host.h
>> @@ -303,4 +303,15 @@ static inline int __init kvmarm_nested_cfg(char *buf)
>>  {
>>   return 0;
>>  }
>> +
>> +static inline int init_nested_virt(void)
>> +{
>> + return 0;
>> +}
>> +
>> +static inline bool nested_virt_in_use(struct kvm_vcpu *vcpu)
>> +{
>> + return false;
>> +}
>> +
>>  #endif /* __ARM_KVM_HOST_H__ */
>> diff --git a/arch/arm64/include/asm/kvm_host.h 
>> b/arch/arm64/include/asm/kvm_host.h
>> index 6df0c7c..86d4b6c 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -387,5 +387,7 @@ static inline void __cpu_init_stage2(void)
>>  }
>>
>>  int __init kvmarm_nested_cfg(char *buf);
>> +int init_nested_virt(void);
>> +bool nested_virt_in_use(struct kvm_vcpu *vcpu);
>>
>>  #endif /* __ARM64_KVM_HOST_H__ */
>> diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
>> index 79f38da..9a05c76 100644
>> --- a/arch/arm64/kvm/nested.c
>> +++ b/arch/arm64/kvm/nested.c
>> @@ -24,3 +24,20 @@ int __init kvmarm_nested_cfg(char *buf)
>>  {
>>   return strtobool(buf, _param);
>>  }
>> +
>> +int init_nested_virt(void)
>> +{
>> + if (nested_param && cpus_have_const_cap(ARM64_HAS_NESTED_VIRT))
>> + kvm_info("Nested virtualization is supported\n");
>> +
>> + return 0;
>> +}
>> +
>> +bool nested_virt_in_use(struct kvm_vcpu *vcpu)
>> +{
>> + if (nested_param && cpus_have_const_cap(ARM64_HAS_NESTED_VIRT)
>> + && test_bit(KVM_ARM_VCPU_NESTED_VIRT, vcpu->arch.features))
>> + return true;
>
> you could initialize a bool in init_nested_virt which you then check
> here to avoid duplicating the logic.

I can make a bool to check the kernel param and the capability. The
third one is per VM given by the userspace, so we don't know it when
we initialize the host hypervisor. We can potentially have a bool in
kvm_vcpu_arch or kvm_arch to cache the whole three conditions, if that
sounds ok.

>
>> +
>> + return false;
>> +}
>> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
>> index 1c1c772..36aae3a 100644
>> --- a/virt/kvm/arm/arm.c
>> +++ b/virt/kvm/arm/arm.c
>> @@ -1478,6 +1478,10 @@ int kvm_arch_init(void *opaque)
>>   if (err)
>>   goto out_err;
>>
>> + err = init_nested_virt();
>> + if (err)
>> + return err;
>> +
>>   err = init_subsystems();
>>   if (err)
>>   goto out_hyp;
>> --
>> 1.9.1
>>
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [RFC PATCH v2 02/38] KVM: arm/arm64: Enable nested virtualization via command-line

2017-08-01 Thread Jintack Lim
On Sun, Jul 30, 2017 at 3:59 PM, Christoffer Dall <cd...@linaro.org> wrote:
> On Tue, Jul 18, 2017 at 11:58:28AM -0500, Jintack Lim wrote:
>> Add a new kernel parameter(kvm-arm.nested) to enable KVM/ARM nested
>> virtualization support. This kernel parameter on arm architecture is
>> ignored since nested virtualization is not supported on arm.
>>
>> Note that this kernel parameter will not have any impact until nested
>> virtualization support is completed. Just add this parameter first to
>> use it when implementing nested virtualization support.
>>
>> Signed-off-by: Jintack Lim <jintack@linaro.org>
>> ---
>>  Documentation/admin-guide/kernel-parameters.txt |  4 
>>  arch/arm/include/asm/kvm_host.h |  4 
>>  arch/arm64/include/asm/kvm_host.h   |  2 ++
>>  arch/arm64/kvm/Makefile |  2 ++
>>  arch/arm64/kvm/nested.c | 26 
>> +
>>  virt/kvm/arm/arm.c  |  2 ++
>>  6 files changed, 40 insertions(+)
>>  create mode 100644 arch/arm64/kvm/nested.c
>>
>> diff --git a/Documentation/admin-guide/kernel-parameters.txt 
>> b/Documentation/admin-guide/kernel-parameters.txt
>> index aa8341e..8fb152d 100644
>> --- a/Documentation/admin-guide/kernel-parameters.txt
>> +++ b/Documentation/admin-guide/kernel-parameters.txt
>> @@ -1841,6 +1841,10 @@
>>   [KVM,ARM] Trap guest accesses to GICv3 common
>>   system registers
>>
>> + kvm-arm.nested=
>> + [KVM,ARM] Allow nested virtualization in KVM/ARM.
>> + Default is 0 (disabled)
>
> We may want to say "on systems that support it" or something like that
> here as well.
>

Sounds good! Thanks.

>> +
>>   kvm-intel.ept=  [KVM,Intel] Disable extended page tables
>>   (virtualized MMU) support on capable Intel chips.
>>   Default is 1 (enabled)
>> diff --git a/arch/arm/include/asm/kvm_host.h 
>> b/arch/arm/include/asm/kvm_host.h
>> index 127e2dd..00b0f97 100644
>> --- a/arch/arm/include/asm/kvm_host.h
>> +++ b/arch/arm/include/asm/kvm_host.h
>> @@ -299,4 +299,8 @@ int kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu,
>>  int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu,
>>  struct kvm_device_attr *attr);
>>
>> +static inline int __init kvmarm_nested_cfg(char *buf)
>> +{
>> + return 0;
>> +}
>>  #endif /* __ARM_KVM_HOST_H__ */
>> diff --git a/arch/arm64/include/asm/kvm_host.h 
>> b/arch/arm64/include/asm/kvm_host.h
>> index 0c4fd1f..dcc4df8 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -386,4 +386,6 @@ static inline void __cpu_init_stage2(void)
>> "PARange is %d bits, unsupported configuration!", parange);
>>  }
>>
>> +int __init kvmarm_nested_cfg(char *buf);
>> +
>>  #endif /* __ARM64_KVM_HOST_H__ */
>> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
>> index 5d98100..f513047 100644
>> --- a/arch/arm64/kvm/Makefile
>> +++ b/arch/arm64/kvm/Makefile
>> @@ -35,3 +35,5 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-debug.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/irqchip.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
>>  kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
>> +
>> +kvm-$(CONFIG_KVM_ARM_HOST) += nested.o
>> diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
>> new file mode 100644
>> index 000..79f38da
>> --- /dev/null
>> +++ b/arch/arm64/kvm/nested.c
>> @@ -0,0 +1,26 @@
>> +/*
>> + * Copyright (C) 2017 - Columbia University and Linaro Ltd.
>> + * Author: Jintack Lim <jintack@linaro.org>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include 
&

Re: [RFC PATCH v2 04/38] KVM: arm/arm64: Check if nested virtualization is in use

2017-08-01 Thread Jintack Lim
On Sun, Jul 30, 2017 at 3:59 PM, Christoffer Dall <cd...@linaro.org> wrote:
> On Tue, Jul 18, 2017 at 11:58:30AM -0500, Jintack Lim wrote:
>> Nested virtualizaion is in use only if all three conditions are met:
>> - The architecture supports nested virtualization.
>> - The kernel parameter is set.
>> - The userspace uses nested virtualiztion feature.
>>
>> Signed-off-by: Jintack Lim <jintack@linaro.org>
>> ---
>>  arch/arm/include/asm/kvm_host.h   | 11 +++
>>  arch/arm64/include/asm/kvm_host.h |  2 ++
>>  arch/arm64/kvm/nested.c   | 17 +
>>  virt/kvm/arm/arm.c|  4 
>>  4 files changed, 34 insertions(+)
>>
>> diff --git a/arch/arm/include/asm/kvm_host.h 
>> b/arch/arm/include/asm/kvm_host.h
>> index 00b0f97..7e9e6c8 100644
>> --- a/arch/arm/include/asm/kvm_host.h
>> +++ b/arch/arm/include/asm/kvm_host.h
>> @@ -303,4 +303,15 @@ static inline int __init kvmarm_nested_cfg(char *buf)
>>  {
>>   return 0;
>>  }
>> +
>> +static inline int init_nested_virt(void)
>> +{
>> + return 0;
>> +}
>> +
>> +static inline bool nested_virt_in_use(struct kvm_vcpu *vcpu)
>> +{
>> + return false;
>> +}
>> +
>>  #endif /* __ARM_KVM_HOST_H__ */
>> diff --git a/arch/arm64/include/asm/kvm_host.h 
>> b/arch/arm64/include/asm/kvm_host.h
>> index 6df0c7c..86d4b6c 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -387,5 +387,7 @@ static inline void __cpu_init_stage2(void)
>>  }
>>
>>  int __init kvmarm_nested_cfg(char *buf);
>> +int init_nested_virt(void);
>> +bool nested_virt_in_use(struct kvm_vcpu *vcpu);
>>
>>  #endif /* __ARM64_KVM_HOST_H__ */
>> diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
>> index 79f38da..9a05c76 100644
>> --- a/arch/arm64/kvm/nested.c
>> +++ b/arch/arm64/kvm/nested.c
>> @@ -24,3 +24,20 @@ int __init kvmarm_nested_cfg(char *buf)
>>  {
>>   return strtobool(buf, _param);
>>  }
>> +
>> +int init_nested_virt(void)
>> +{
>> + if (nested_param && cpus_have_const_cap(ARM64_HAS_NESTED_VIRT))
>> + kvm_info("Nested virtualization is supported\n");
>> +
>> + return 0;
>> +}
>> +
>> +bool nested_virt_in_use(struct kvm_vcpu *vcpu)
>> +{
>> + if (nested_param && cpus_have_const_cap(ARM64_HAS_NESTED_VIRT)
>> + && test_bit(KVM_ARM_VCPU_NESTED_VIRT, vcpu->arch.features))
>> + return true;
>> +
>> + return false;
>> +}
>
> after reading through a lot of your patches, I feel like vm_has_el2()
> would be a more elegant name, but it's not a strict requirement to
> change it.

I think it's a nice name. Let me think about it :)

>
>> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
>> index 1c1c772..36aae3a 100644
>> --- a/virt/kvm/arm/arm.c
>> +++ b/virt/kvm/arm/arm.c
>> @@ -1478,6 +1478,10 @@ int kvm_arch_init(void *opaque)
>>   if (err)
>>   goto out_err;
>>
>> + err = init_nested_virt();
>> + if (err)
>> + return err;
>> +
>>   err = init_subsystems();
>>   if (err)
>>   goto out_hyp;
>> --
>> 1.9.1
>>
>
> Thanks,
> -Christoffer
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [RFC PATCH v2 00/38] Nested Virtualization on KVM/ARM

2017-07-28 Thread Jintack Lim
On Fri, Jul 28, 2017 at 4:13 PM, Bandan Das <b...@redhat.com> wrote:
> Jintack Lim <jintack@linaro.org> writes:
> ...
>>>
>>> I'll share my experiment setup shortly.
>>
>> I summarized my experiment setup here.
>>
>> https://github.com/columbia/nesting-pub/wiki/Nested-virtualization-on-ARM-setup
>
> Thanks Jintack! I was able to test L2 boot up with these instructions.

Thanks for the confirmation!

>
> Next, I will try to run some simple tests. Any suggestions on reducing the L2 
> bootup
> time in my test setup ? I think I will try to make the L2 kernel print
> less messages; and maybe just get rid of some of the userspace services.
> I also applied the patch to reduce the timer frequency btw.

I think you can try to use those kernel parameters: "loglevel=1", with
which the kernel print (almost) nothing during the boot process but
the init process will print something,  or "console=none", with which
you don't see anything but the login message.  I didn't used them
because I wanted to see the L2 boot message as soon as possible :)

Thanks,
Jintack

>
> Bandan
>
>>>
>>> Even though this work has some limitations and TODOs, I'd appreciate early
>>> feedback on this RFC. Specifically, I'm interested in:
>>>
>>> - Overall design to manage vcpu context for the virtual EL2
>>> - Verifying correct EL2 register configurations such as HCR_EL2, CPTR_EL2
>>>   (Patch 30 and 32)
>>> - Patch organization and coding style
>>
>> I also wonder if the hardware and/or KVM do not support nested
>> virtualization but the userspace uses nested virtualization option,
>> which one is better: giving an error or launching a regular VM
>> silently.
>>
>>>
>>> This patch series is based on kvm/next d38338e.
>>> The whole patch series including memory, VGIC, and timer patches is 
>>> available
>>> here:
>>>
>>> g...@github.com:columbia/nesting-pub.git rfc-v2
>>>
>>> Limitations:
>>> - There are some cases that the target exception level of a VM is ambiguous 
>>> when
>>>   emulating eret instruction. I'm discussing this issue with Christoffer and
>>>   Marc. Meanwhile, I added a temporary patch (not included in this
>>>   series. f1beaba in the repo) and used 4.10.0 kernel when testing the guest
>>>   hypervisor with VHE.
>>> - Recursive nested virtualization is not tested yet.
>>> - Other hypervisors (such as Xen) on KVM are not tested.
>>>
>>> TODO:
>>> - Submit memory, VGIC, and timer patches
>>> - Evaluate regular VM performance to see if there's a negative impact.
>>> - Test other hypervisors such as Xen on KVM
>>> - Test recursive nested virtualization
>>>
>>> v1-->v2:
>>> - Added support for the virtual EL2 with VHE
>>> - Rewrote commit messages and comments from the perspective of supporting
>>>   execution environments to VMs, rather than from the perspective of the 
>>> guest
>>>   hypervisor running in them.
>>> - Fixed a few bugs to make it run on the FastModel.
>>> - Tested on ARMv8.3 with four configurations. (host/guest. with/without 
>>> VHE.)
>>> - Rebased to kvm/next
>>>
>>> [1] 
>>> https://www.community.arm.com/processors/b/blog/posts/armv8-a-architecture-2016-additions
>>>
>>> Christoffer Dall (7):
>>>   KVM: arm64: Add KVM nesting feature
>>>   KVM: arm64: Allow userspace to set PSR_MODE_EL2x
>>>   KVM: arm64: Add vcpu_mode_el2 primitive to support nesting
>>>   KVM: arm/arm64: Add a framework to prepare virtual EL2 execution
>>>   arm64: Add missing TCR hw defines
>>>   KVM: arm64: Create shadow EL1 registers
>>>   KVM: arm64: Trap EL1 VM register accesses in virtual EL2
>>>
>>> Jintack Lim (31):
>>>   arm64: Add ARM64_HAS_NESTED_VIRT feature
>>>   KVM: arm/arm64: Enable nested virtualization via command-line
>>>   KVM: arm/arm64: Check if nested virtualization is in use
>>>   KVM: arm64: Add EL2 system registers to vcpu context
>>>   KVM: arm64: Add EL2 special registers to vcpu context
>>>   KVM: arm64: Add the shadow context for virtual EL2 execution
>>>   KVM: arm64: Set vcpu context depending on the guest exception level
>>>   KVM: arm64: Synchronize EL1 system registers on virtual EL2 entry and
>>> exit
>>>   KVM: arm64: Move exception macros and enums to a common file
>>>   KVM: arm64: Support to inject exceptions to the virtual EL2
>>>

Re: [RFC PATCH v2 00/38] Nested Virtualization on KVM/ARM

2017-07-19 Thread Jintack Lim
On Wed, Jul 19, 2017 at 4:49 AM, Christoffer Dall <cd...@linaro.org> wrote:
> Hi Jintack,
>
> On Tue, Jul 18, 2017 at 10:23:05PM -0400, Jintack Lim wrote:
>> On Tue, Jul 18, 2017 at 12:58 PM, Jintack Lim <jintack@linaro.org> wrote:
>> > Nested virtualization is the ability to run a virtual machine inside 
>> > another
>> > virtual machine. In other words, it’s about running a hypervisor (the guest
>> > hypervisor) on top of another hypervisor (the host hypervisor).
>> >
>> > Supporting nested virtualization on ARM means that the hypervisor provides 
>> > not
>> > only EL0/EL1 execution environment to VMs as it usually does but also the
>> > virtualization extensions including EL2 execution environment. Once the 
>> > host
>> > hypervisor provides those execution environments to the VMs, then the guest
>> > hypervisor can run its own VMs (nested VMs) naturally.
>> >
>> > This series supports nested virtualization on arm64. ARM recently 
>> > announced an
>> > extension (ARMv8.3) which has support for nested virtualization[1]. This 
>> > patch
>> > set is based on the ARMv8.3 specification and tested on the FastModel with
>> > ARMv8.3 extension.
>> >
>> > The whole patch set to support nested virtualization is huge over 70
>> > patches, so I categorized them into four parts: CPU, memory, VGIC, and 
>> > timer
>> > virtualization. This patch series is the first part.
>> >
>> > CPU virtualization patch series provides basic nested virtualization 
>> > framework
>> > and instruction emulations including v8.1 VHE feature and v8.3 nested
>> > virtualization feature for VMs.
>> >
>> > This patch series again can be divided into four parts. Patch 1 to 5 
>> > introduces
>> > nested virtualization by discovering hardware feature, adding a kernel
>> > parameter and allowing the userspace to set the initial CPU mode to EL2.
>> >
>> > Patch 6 to 25 are to support the EL2 execution environment, the virtual 
>> > EL2, to
>> > a VM on v8.0 architecture. We de-privilege the guest hypervisor and 
>> > emulate the
>> > virtual EL2 mode in EL1 using the hardware features provided by ARMv8.3; 
>> > The
>> > host hypervisor manages virtual EL2 register state for the guest hypervisor
>> > and shadow EL1 register state that reflects the virtual EL2 register state 
>> > to
>> > run the guest hypervisor in EL1.
>> >
>> > Patch 26 to 33 add support for the virtual EL2 with Virtualization Host
>> > Extensions. These patches emulate newly defined registers and bits in v8.1 
>> > and
>> > allow the virtual EL2 to access EL2 register states via EL1 register 
>> > accesses
>> > as in the real EL2.
>> >
>> > Patch 34 to 38 are to support for the virtual EL2 with nested 
>> > virtualization.
>> > These enable recursive nested virtualization.
>> >
>> > This patch set is tested on the FastModel with the v8.3 extension for 
>> > arm64 and
>> > a cubietruck for arm32. On the FastModel, the host and the guest kernels 
>> > are
>> > compiled with and without VHE, so there are four combinations. I was able 
>> > to
>> > boot SMP Linux in the nested VM on all four configurations and able to run
>> > hackbench. I also checked that regular VMs could boot when the nested
>> > virtualization kernel parameter was not set. On the cubietruck, I also 
>> > verified
>> > that regular VMs could boot as well.
>> >
>> > I'll share my experiment setup shortly.
>>
>> I summarized my experiment setup here.
>>
>> https://github.com/columbia/nesting-pub/wiki/Nested-virtualization-on-ARM-setup
>>
>
> Thanks for sharing this.
>
>> >
>> > Even though this work has some limitations and TODOs, I'd appreciate early
>> > feedback on this RFC. Specifically, I'm interested in:
>> >
>> > - Overall design to manage vcpu context for the virtual EL2
>> > - Verifying correct EL2 register configurations such as HCR_EL2, CPTR_EL2
>> >   (Patch 30 and 32)
>> > - Patch organization and coding style
>>
>> I also wonder if the hardware and/or KVM do not support nested
>> virtualization but the userspace uses nested virtualization option,
>> which one is better: giving an error or launching a regular VM
>> silently.
>>
>
> I think KVM should complain to userspace if userspace tries to set a
> feature it does not support, and I think userspace should give as
> meaningful an error message as possible to the user when that happens.
>

Ok, thanks. I'll work this out.

> Thanks,
> -Christoffer
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [RFC PATCH v2 37/38] KVM: arm64: Respect the virtual HCR_EL2.NV1 bit setting

2017-07-18 Thread Jintack Lim
On Tue, Jul 18, 2017 at 12:59 PM, Jintack Lim <jintack@linaro.org> wrote:
> Forward ELR_EL1, SPSR_EL1 and VBAR_EL1 traps to the virtual EL2 if the
> virtual HCR_EL2.NV bit is set.
>
> This is for recursive nested virtualization.
>
> Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>

This should be linaro e-mail address. Will fix it.

> ---
>  arch/arm64/include/asm/kvm_arm.h |  1 +
>  arch/arm64/kvm/sys_regs.c| 18 ++
>  2 files changed, 19 insertions(+)
>
> diff --git a/arch/arm64/include/asm/kvm_arm.h 
> b/arch/arm64/include/asm/kvm_arm.h
> index aeaac4e..a1274b7 100644
> --- a/arch/arm64/include/asm/kvm_arm.h
> +++ b/arch/arm64/include/asm/kvm_arm.h
> @@ -23,6 +23,7 @@
>  #include 
>
>  /* Hyp Configuration Register (HCR) bits */
> +#define HCR_NV1(UL(1) << 43)
>  #define HCR_NV (UL(1) << 42)
>  #define HCR_E2H(UL(1) << 34)
>  #define HCR_ID (UL(1) << 33)
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 3e4ec5e..6f67666 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -1031,6 +1031,15 @@ static bool trap_el2_regs(struct kvm_vcpu *vcpu,
> return true;
>  }
>
> +/* This function is to support the recursive nested virtualization */
> +static bool forward_nv1_traps(struct kvm_vcpu *vcpu, struct sys_reg_params 
> *p)
> +{
> +   if (!vcpu_mode_el2(vcpu) && (vcpu_sys_reg(vcpu, HCR_EL2) & HCR_NV1))
> +   return true;
> +
> +   return false;
> +}
> +
>  static bool access_elr(struct kvm_vcpu *vcpu,
> struct sys_reg_params *p,
> const struct sys_reg_desc *r)
> @@ -1038,6 +1047,9 @@ static bool access_elr(struct kvm_vcpu *vcpu,
> if (el12_reg(p) && forward_nv_traps(vcpu))
> return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
>
> +   if (!el12_reg(p) && forward_nv1_traps(vcpu, p))
> +   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
> +
> access_rw(p, >arch.ctxt.gp_regs.elr_el1);
> return true;
>  }
> @@ -1049,6 +1061,9 @@ static bool access_spsr(struct kvm_vcpu *vcpu,
> if (el12_reg(p) && forward_nv_traps(vcpu))
> return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
>
> +   if (!el12_reg(p) && forward_nv1_traps(vcpu, p))
> +   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
> +
> access_rw(p, >arch.ctxt.gp_regs.spsr[KVM_SPSR_EL1]);
> return true;
>  }
> @@ -1060,6 +1075,9 @@ static bool access_vbar(struct kvm_vcpu *vcpu,
> if (el12_reg(p) && forward_nv_traps(vcpu))
> return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
>
> +   if (!el12_reg(p) && forward_nv1_traps(vcpu, p))
> +   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
> +
> access_rw(p, _sys_reg(vcpu, r->reg));
> return true;
>  }
> --
> 1.9.1
>

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [RFC PATCH v2 00/38] Nested Virtualization on KVM/ARM

2017-07-18 Thread Jintack Lim
On Tue, Jul 18, 2017 at 12:58 PM, Jintack Lim <jintack@linaro.org> wrote:
> Nested virtualization is the ability to run a virtual machine inside another
> virtual machine. In other words, it’s about running a hypervisor (the guest
> hypervisor) on top of another hypervisor (the host hypervisor).
>
> Supporting nested virtualization on ARM means that the hypervisor provides not
> only EL0/EL1 execution environment to VMs as it usually does but also the
> virtualization extensions including EL2 execution environment. Once the host
> hypervisor provides those execution environments to the VMs, then the guest
> hypervisor can run its own VMs (nested VMs) naturally.
>
> This series supports nested virtualization on arm64. ARM recently announced an
> extension (ARMv8.3) which has support for nested virtualization[1]. This patch
> set is based on the ARMv8.3 specification and tested on the FastModel with
> ARMv8.3 extension.
>
> The whole patch set to support nested virtualization is huge over 70
> patches, so I categorized them into four parts: CPU, memory, VGIC, and timer
> virtualization. This patch series is the first part.
>
> CPU virtualization patch series provides basic nested virtualization framework
> and instruction emulations including v8.1 VHE feature and v8.3 nested
> virtualization feature for VMs.
>
> This patch series again can be divided into four parts. Patch 1 to 5 
> introduces
> nested virtualization by discovering hardware feature, adding a kernel
> parameter and allowing the userspace to set the initial CPU mode to EL2.
>
> Patch 6 to 25 are to support the EL2 execution environment, the virtual EL2, 
> to
> a VM on v8.0 architecture. We de-privilege the guest hypervisor and emulate 
> the
> virtual EL2 mode in EL1 using the hardware features provided by ARMv8.3; The
> host hypervisor manages virtual EL2 register state for the guest hypervisor
> and shadow EL1 register state that reflects the virtual EL2 register state to
> run the guest hypervisor in EL1.
>
> Patch 26 to 33 add support for the virtual EL2 with Virtualization Host
> Extensions. These patches emulate newly defined registers and bits in v8.1 and
> allow the virtual EL2 to access EL2 register states via EL1 register accesses
> as in the real EL2.
>
> Patch 34 to 38 are to support for the virtual EL2 with nested virtualization.
> These enable recursive nested virtualization.
>
> This patch set is tested on the FastModel with the v8.3 extension for arm64 
> and
> a cubietruck for arm32. On the FastModel, the host and the guest kernels are
> compiled with and without VHE, so there are four combinations. I was able to
> boot SMP Linux in the nested VM on all four configurations and able to run
> hackbench. I also checked that regular VMs could boot when the nested
> virtualization kernel parameter was not set. On the cubietruck, I also 
> verified
> that regular VMs could boot as well.
>
> I'll share my experiment setup shortly.

I summarized my experiment setup here.

https://github.com/columbia/nesting-pub/wiki/Nested-virtualization-on-ARM-setup

>
> Even though this work has some limitations and TODOs, I'd appreciate early
> feedback on this RFC. Specifically, I'm interested in:
>
> - Overall design to manage vcpu context for the virtual EL2
> - Verifying correct EL2 register configurations such as HCR_EL2, CPTR_EL2
>   (Patch 30 and 32)
> - Patch organization and coding style

I also wonder if the hardware and/or KVM do not support nested
virtualization but the userspace uses nested virtualization option,
which one is better: giving an error or launching a regular VM
silently.

>
> This patch series is based on kvm/next d38338e.
> The whole patch series including memory, VGIC, and timer patches is available
> here:
>
> g...@github.com:columbia/nesting-pub.git rfc-v2
>
> Limitations:
> - There are some cases that the target exception level of a VM is ambiguous 
> when
>   emulating eret instruction. I'm discussing this issue with Christoffer and
>   Marc. Meanwhile, I added a temporary patch (not included in this
>   series. f1beaba in the repo) and used 4.10.0 kernel when testing the guest
>   hypervisor with VHE.
> - Recursive nested virtualization is not tested yet.
> - Other hypervisors (such as Xen) on KVM are not tested.
>
> TODO:
> - Submit memory, VGIC, and timer patches
> - Evaluate regular VM performance to see if there's a negative impact.
> - Test other hypervisors such as Xen on KVM
> - Test recursive nested virtualization
>
> v1-->v2:
> - Added support for the virtual EL2 with VHE
> - Rewrote commit messages and comments from the perspective of supporting
>   execution environments to VMs, rather than from the perspective of the

[RFC PATCH v2 37/38] KVM: arm64: Respect the virtual HCR_EL2.NV1 bit setting

2017-07-18 Thread Jintack Lim
Forward ELR_EL1, SPSR_EL1 and VBAR_EL1 traps to the virtual EL2 if the
virtual HCR_EL2.NV bit is set.

This is for recursive nested virtualization.

Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>
---
 arch/arm64/include/asm/kvm_arm.h |  1 +
 arch/arm64/kvm/sys_regs.c| 18 ++
 2 files changed, 19 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index aeaac4e..a1274b7 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -23,6 +23,7 @@
 #include 
 
 /* Hyp Configuration Register (HCR) bits */
+#define HCR_NV1(UL(1) << 43)
 #define HCR_NV (UL(1) << 42)
 #define HCR_E2H(UL(1) << 34)
 #define HCR_ID (UL(1) << 33)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 3e4ec5e..6f67666 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1031,6 +1031,15 @@ static bool trap_el2_regs(struct kvm_vcpu *vcpu,
return true;
 }
 
+/* This function is to support the recursive nested virtualization */
+static bool forward_nv1_traps(struct kvm_vcpu *vcpu, struct sys_reg_params *p)
+{
+   if (!vcpu_mode_el2(vcpu) && (vcpu_sys_reg(vcpu, HCR_EL2) & HCR_NV1))
+   return true;
+
+   return false;
+}
+
 static bool access_elr(struct kvm_vcpu *vcpu,
struct sys_reg_params *p,
const struct sys_reg_desc *r)
@@ -1038,6 +1047,9 @@ static bool access_elr(struct kvm_vcpu *vcpu,
if (el12_reg(p) && forward_nv_traps(vcpu))
return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
 
+   if (!el12_reg(p) && forward_nv1_traps(vcpu, p))
+   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+
access_rw(p, >arch.ctxt.gp_regs.elr_el1);
return true;
 }
@@ -1049,6 +1061,9 @@ static bool access_spsr(struct kvm_vcpu *vcpu,
if (el12_reg(p) && forward_nv_traps(vcpu))
return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
 
+   if (!el12_reg(p) && forward_nv1_traps(vcpu, p))
+   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+
access_rw(p, >arch.ctxt.gp_regs.spsr[KVM_SPSR_EL1]);
return true;
 }
@@ -1060,6 +1075,9 @@ static bool access_vbar(struct kvm_vcpu *vcpu,
if (el12_reg(p) && forward_nv_traps(vcpu))
return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
 
+   if (!el12_reg(p) && forward_nv1_traps(vcpu, p))
+   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+
access_rw(p, _sys_reg(vcpu, r->reg));
return true;
 }
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 23/38] KVM: arm64: Inject HVC exceptions to the virtual EL2

2017-07-18 Thread Jintack Lim
Now that the psci call is done by the smc instruction when nested
virtualization is enabled, it is clear that all hvc instruction from the
VM (including from the virtual EL2) are supposed to handled in the
virtual EL2.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/handle_exit.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 6cf6b93..8b398b2 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -42,6 +42,12 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run 
*run)
kvm_vcpu_hvc_get_imm(vcpu));
vcpu->stat.hvc_exit_stat++;
 
+   /* Forward hvc instructions to the virtual EL2 if the guest has EL2. */
+   if (nested_virt_in_use(vcpu)) {
+   kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+   return 1;
+   }
+
ret = kvm_psci_call(vcpu);
if (ret < 0) {
kvm_inject_undefined(vcpu);
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 38/38] KVM: arm64: Respect the virtual CPTR_EL2.TCPAC setting

2017-07-18 Thread Jintack Lim
Forward CPACR_EL1 traps to the virtual EL2 if virtual CPTR_EL2 is
configured to trap CPACR_EL1 accesses from EL1.

This is for recursive nested virtualization.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 6f67666..ba2966d 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1091,6 +1091,11 @@ static bool access_cpacr(struct kvm_vcpu *vcpu,
if (el12_reg(p) && forward_nv_traps(vcpu))
return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
 
+   /* Forward this trap to the virtual EL2 if CPTR_EL2.TCPAC is set*/
+   if (!el12_reg(p) && !vcpu_mode_el2(vcpu) &&
+   (vcpu_sys_reg(vcpu, CPTR_EL2) & CPTR_EL2_TCPAC))
+   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+
/*
 * When the virtual HCR_EL2.E2H == 1, an access to CPACR_EL1
 * in the virtual EL2 is to access CPTR_EL2.
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 34/38] KVM: arm64: Respect the virtual HCR_EL2.NV bit setting

2017-07-18 Thread Jintack Lim
Forward traps due to HCR_EL2.NV bit to the virtual EL2 if they are not
coming from the virtual EL2 and the virtual HCR_EL2.NV bit is set.

This is for recursive nested virtualization.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_arm.h|  1 +
 arch/arm64/include/asm/kvm_coproc.h |  1 +
 arch/arm64/kvm/handle_exit.c| 13 +
 arch/arm64/kvm/sys_regs.c   | 22 ++
 4 files changed, 37 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 6e99978..aeaac4e 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -23,6 +23,7 @@
 #include 
 
 /* Hyp Configuration Register (HCR) bits */
+#define HCR_NV (UL(1) << 42)
 #define HCR_E2H(UL(1) << 34)
 #define HCR_ID (UL(1) << 33)
 #define HCR_CD (UL(1) << 32)
diff --git a/arch/arm64/include/asm/kvm_coproc.h 
b/arch/arm64/include/asm/kvm_coproc.h
index 1b3d21b..6223df6 100644
--- a/arch/arm64/include/asm/kvm_coproc.h
+++ b/arch/arm64/include/asm/kvm_coproc.h
@@ -44,6 +44,7 @@ void kvm_register_target_sys_reg_table(unsigned int target,
 int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
 int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
 int kvm_handle_sys(struct kvm_vcpu *vcpu, struct kvm_run *run);
+bool forward_nv_traps(struct kvm_vcpu *vcpu);
 
 #define kvm_coproc_table_init kvm_sys_reg_table_init
 void kvm_sys_reg_table_init(void);
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index d4e7b2b..fccd9d6 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -61,6 +61,12 @@ static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run 
*run)
 {
int ret;
 
+   /*
+* Forward this trapped smc instruction to the virtual EL2.
+*/
+   if (forward_nv_traps(vcpu) && (vcpu_sys_reg(vcpu, HCR_EL2) & HCR_TSC))
+   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+
/* If imm is non-zero, it's not defined */
if (kvm_vcpu_hvc_get_imm(vcpu)) {
kvm_inject_undefined(vcpu);
@@ -197,6 +203,13 @@ static int kvm_handle_eret(struct kvm_vcpu *vcpu, struct 
kvm_run *run)
  vcpu_el2_sreg(vcpu, SPSR_EL2));
 
/*
+* Forward this trap to the virtual EL2 if the virtual HCR_EL2.NV
+* bit is set.
+*/
+   if (forward_nv_traps(vcpu))
+   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+
+   /*
 * Note that the current exception level is always the virtual EL2,
 * since we set HCR_EL2.NV bit only when entering the virtual EL2.
 */
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 910b50d..4fd7090 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -939,6 +939,14 @@ static bool access_cntp_cval(struct kvm_vcpu *vcpu,
return true;
 }
 
+/* This function is to support the recursive nested virtualization */
+bool forward_nv_traps(struct kvm_vcpu *vcpu)
+{
+   if (!vcpu_mode_el2(vcpu) && (vcpu_sys_reg(vcpu, HCR_EL2) & HCR_NV))
+   return true;
+   return false;
+}
+
 static inline void access_rw(struct sys_reg_params *p, u64 *sysreg)
 {
if (!p->is_write)
@@ -977,6 +985,13 @@ static bool trap_el2_regs(struct kvm_vcpu *vcpu,
 {
u64 *sys_reg;
 
+   /*
+* Forward this trap to the virtual EL2 if the virtual HCR_EL2.NV
+* bit is set.
+*/
+   if (forward_nv_traps(vcpu))
+   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+
sys_reg = get_special_reg(vcpu, p);
if (!sys_reg)
sys_reg = _sys_reg(vcpu, r->reg);
@@ -1914,6 +1929,13 @@ static int emulate_sys_instr(struct kvm_vcpu *vcpu,
 {
int ret = 0;
 
+   /*
+* Forward this trap to the virtual EL2 if the virtual HCR_EL2.NV
+* bit is set.
+*/
+   if (forward_nv_traps(vcpu))
+   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+
/* TLB maintenance instructions*/
if (params->CRn == 0b1000)
ret = emulate_tlbi(vcpu, params);
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 35/38] KVM: arm64: Respect the virtual HCR_EL2.NV bit setting for EL12 register traps

2017-07-18 Thread Jintack Lim
In addition to EL2 register accesses, setting NV bit will also make EL12
register accesses trap to EL2. To emulate this for the virtual EL2,
forword traps due to EL12 register accessses to the virtual EL2 if the
virtual HCR_EL2.NV bit is set.

This is for recursive nested virtualization.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 18 ++
 1 file changed, 18 insertions(+)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 4fd7090..3559cf7 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -149,6 +149,9 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
int i;
const struct el1_el2_map *map;
 
+   if (el12_reg(p) && forward_nv_traps(vcpu))
+   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+
/*
 * Redirect EL1 register accesses to the corresponding EL2 registers if
 * they are meant to access EL2 registers.
@@ -959,6 +962,9 @@ static bool access_cntkctl_el12(struct kvm_vcpu *vcpu,
 struct sys_reg_params *p,
 const struct sys_reg_desc *r)
 {
+   if (forward_nv_traps(vcpu))
+   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+
access_rw(p, _sys_reg(vcpu, r->reg));
return true;
 }
@@ -1005,6 +1011,9 @@ static bool access_elr(struct kvm_vcpu *vcpu,
struct sys_reg_params *p,
const struct sys_reg_desc *r)
 {
+   if (el12_reg(p) && forward_nv_traps(vcpu))
+   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+
access_rw(p, >arch.ctxt.gp_regs.elr_el1);
return true;
 }
@@ -1013,6 +1022,9 @@ static bool access_spsr(struct kvm_vcpu *vcpu,
struct sys_reg_params *p,
const struct sys_reg_desc *r)
 {
+   if (el12_reg(p) && forward_nv_traps(vcpu))
+   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+
access_rw(p, >arch.ctxt.gp_regs.spsr[KVM_SPSR_EL1]);
return true;
 }
@@ -1021,6 +1033,9 @@ static bool access_vbar(struct kvm_vcpu *vcpu,
struct sys_reg_params *p,
const struct sys_reg_desc *r)
 {
+   if (el12_reg(p) && forward_nv_traps(vcpu))
+   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+
access_rw(p, _sys_reg(vcpu, r->reg));
return true;
 }
@@ -1031,6 +1046,9 @@ static bool access_cpacr(struct kvm_vcpu *vcpu,
 {
u64 reg = sys_reg(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
 
+   if (el12_reg(p) && forward_nv_traps(vcpu))
+   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+
/*
 * When the virtual HCR_EL2.E2H == 1, an access to CPACR_EL1
 * in the virtual EL2 is to access CPTR_EL2.
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 33/38] KVM: arm64: Emulate appropriate VM control system registers

2017-07-18 Thread Jintack Lim
Now that the virtual EL2 can access EL2 register states via EL1
registers, we need to consider it when selecting the register to
emulate.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 46 --
 1 file changed, 44 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 79980be..910b50d 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -110,6 +110,31 @@ static bool access_dcsw(struct kvm_vcpu *vcpu,
return true;
 }
 
+struct el1_el2_map {
+   int el1;
+   int el2;
+};
+
+static const struct el1_el2_map vm_map[] = {
+   {SCTLR_EL1, SCTLR_EL2},
+   {TTBR0_EL1, TTBR0_EL2},
+   {TTBR1_EL1, TTBR1_EL2},
+   {TCR_EL1, TCR_EL2},
+   {ESR_EL1, ESR_EL2},
+   {FAR_EL1, FAR_EL2},
+   {AFSR0_EL1, AFSR0_EL2},
+   {AFSR1_EL1, AFSR1_EL2},
+   {MAIR_EL1, MAIR_EL2},
+   {AMAIR_EL1, AMAIR_EL2},
+   {CONTEXTIDR_EL1, CONTEXTIDR_EL2},
+};
+
+static inline bool el12_reg(struct sys_reg_params *p)
+{
+   /* All *_EL12 registers have Op1=5. */
+   return (p->Op1 == 5);
+}
+
 /*
  * Generic accessor for VM registers. Only called as long as HCR_TVM
  * is set. If the guest enables the MMU, we stop trapping the VM
@@ -120,16 +145,33 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
  const struct sys_reg_desc *r)
 {
bool was_enabled = vcpu_has_cache_enabled(vcpu);
+   u64 *sysreg = _sys_reg(vcpu, r->reg);
+   int i;
+   const struct el1_el2_map *map;
+
+   /*
+* Redirect EL1 register accesses to the corresponding EL2 registers if
+* they are meant to access EL2 registers.
+*/
+   if (vcpu_el2_e2h_is_set(vcpu) && !el12_reg(p)) {
+   for (i = 0; i < ARRAY_SIZE(vm_map); i++) {
+   map = _map[i];
+   if (map->el1 == r->reg) {
+   sysreg = _sys_reg(vcpu, map->el2);
+   break;
+   }
+   }
+   }
 
BUG_ON(!vcpu_mode_el2(vcpu) && !p->is_write);
 
if (!p->is_write) {
-   p->regval = vcpu_sys_reg(vcpu, r->reg);
+   p->regval = *sysreg;
return true;
}
 
if (!p->is_aarch32) {
-   vcpu_sys_reg(vcpu, r->reg) = p->regval;
+   *sysreg = p->regval;
} else {
if (!p->is_32bit)
vcpu_cp15_64_high(vcpu, r->reg) = 
upper_32_bits(p->regval);
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 30/38] KVM: arm64: Allow the virtual EL2 to access EL2 states without trap

2017-07-18 Thread Jintack Lim
When the virtual E2H bit is set, we can support EL2 register accesses
via EL1 registers from the virtual EL2 by doing trap-and-emulate. A
better alternative, however, is to allow the virtual EL2 to access EL2
register states without trap. This can be easily achieved by not traping
EL1 registers since those registers already have EL2 register states.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/hyp/switch.c | 23 +--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index d513da9..fffd0c7 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -74,6 +74,7 @@ static hyp_alternate_select(__activate_traps_arch,
 static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 {
u64 val;
+   u64 vhcr_el2;
 
/*
 * We are about to set CPTR_EL2.TFP to trap all floating point
@@ -89,8 +90,26 @@ static void __hyp_text __activate_traps(struct kvm_vcpu 
*vcpu)
write_sysreg(1 << 30, fpexc32_el2);
isb();
}
-   if (vcpu_mode_el2(vcpu))
-   val |= HCR_TVM | HCR_TRVM;
+
+   if (is_hyp_ctxt(vcpu)) {
+   /*
+* For a guest hypervisor on v8.0, trap and emulate the EL1
+* virtual memory control register accesses.
+*/
+   if (!vcpu_el2_e2h_is_set(vcpu))
+   val |= HCR_TVM | HCR_TRVM;
+   /*
+* For a guest hypervisor on v8.1 (VHE), allow to access the
+* EL1 virtual memory control registers natively. These accesses
+* are to access EL2 register states.
+* Note that we stil need to respect the virtual HCR_EL2 state.
+*/
+   else {
+   vhcr_el2 = vcpu_sys_reg(vcpu, HCR_EL2);
+   val |= vhcr_el2 & (HCR_TVM | HCR_TRVM);
+   }
+   }
+
write_sysreg(val, hcr_el2);
/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
write_sysreg(1 << 15, hstr_el2);
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 24/38] KVM: arm64: Respect virtual HCR_EL2.TWX setting

2017-07-18 Thread Jintack Lim
Forward exceptions due to WFI or WFE instructions to the virtual EL2 if
they are not coming from the virtual EL2 and virtual HCR_EL2.TWX is set.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_host.h |  1 +
 arch/arm64/kvm/handle_exit.c  | 13 -
 arch/arm64/kvm/nested.c   | 20 
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_host.h 
b/arch/arm64/include/asm/kvm_host.h
index 46880c3..53b0b33 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -442,5 +442,6 @@ static inline void __cpu_init_stage2(void)
 int __init kvmarm_nested_cfg(char *buf);
 int init_nested_virt(void);
 bool nested_virt_in_use(struct kvm_vcpu *vcpu);
+int handle_wfx_nested(struct kvm_vcpu *vcpu, bool is_wfe);
 
 #endif /* __ARM64_KVM_HOST_H__ */
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 8b398b2..25ec824 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -107,7 +107,18 @@ static int handle_no_fpsimd(struct kvm_vcpu *vcpu, struct 
kvm_run *run)
  */
 static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-   if (kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WFx_ISS_WFE) {
+   bool is_wfe = !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WFx_ISS_WFE);
+
+   if (nested_virt_in_use(vcpu)) {
+   int ret = handle_wfx_nested(vcpu, is_wfe);
+
+   if (ret < 0 && ret != -EINVAL)
+   return ret;
+   else if (ret >= 0)
+   return ret;
+   }
+
+   if (is_wfe) {
trace_kvm_wfx_arm64(*vcpu_pc(vcpu), true);
vcpu->stat.wfe_exit_stat++;
kvm_vcpu_on_spin(vcpu);
diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index 9a05c76..042d304 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -18,6 +18,8 @@
 #include 
 #include 
 
+#include 
+
 static bool nested_param;
 
 int __init kvmarm_nested_cfg(char *buf)
@@ -41,3 +43,21 @@ bool nested_virt_in_use(struct kvm_vcpu *vcpu)
 
return false;
 }
+
+/*
+ * Inject wfx to the virtual EL2 if this is not from the virtual EL2 and
+ * the virtual HCR_EL2.TWX is set. Otherwise, let the host hypervisor
+ * handle this.
+ */
+int handle_wfx_nested(struct kvm_vcpu *vcpu, bool is_wfe)
+{
+   u64 hcr_el2 = vcpu_sys_reg(vcpu, HCR_EL2);
+
+   if (vcpu_mode_el2(vcpu))
+   return -EINVAL;
+
+   if ((is_wfe && (hcr_el2 & HCR_TWE)) || (!is_wfe && (hcr_el2 & HCR_TWI)))
+   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+
+   return -EINVAL;
+}
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 31/38] KVM: arm64: Manage the shadow states when virtual E2H bit enabled

2017-07-18 Thread Jintack Lim
When creating the shadow context for the virtual EL2 execution, we can
directly copy the EL2 register states to the shadow EL1 register states
if the virtual HCR_EL2.E2H bit is set. This is because EL1 and EL2
system register formats compatible with E2H=1.

Now that we allow the virtual EL2 modify its EL2 registers without trap
via the physical EL1 system register accesses, we need to reflect the
changes made to the EL1 system registers to the virtual EL2 register
states. This is not required to the virtual EL2 without VHE, since the
virtual EL2 should always use _EL2 accessors, which traps to EL2.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/context.c | 67 +++-
 1 file changed, 66 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/context.c b/arch/arm64/kvm/context.c
index 39bd92d..9947bc8 100644
--- a/arch/arm64/kvm/context.c
+++ b/arch/arm64/kvm/context.c
@@ -39,6 +39,27 @@ struct el1_el2_map {
{ VBAR_EL1, VBAR_EL2 },
 };
 
+/*
+ * List of pair of EL1/EL2 registers which are used to access real EL2
+ * registers in EL2 with E2H bit set.
+ */
+static const struct el1_el2_map vhe_map[] = {
+   { SCTLR_EL1, SCTLR_EL2 },
+   { CPACR_EL1, CPTR_EL2 },
+   { TTBR0_EL1, TTBR0_EL2 },
+   { TTBR1_EL1, TTBR1_EL2 },
+   { TCR_EL1, TCR_EL2},
+   { AFSR0_EL1, AFSR0_EL2 },
+   { AFSR1_EL1, AFSR1_EL2 },
+   { ESR_EL1, ESR_EL2},
+   { FAR_EL1, FAR_EL2},
+   { MAIR_EL1, MAIR_EL2 },
+   { AMAIR_EL1, AMAIR_EL2 },
+   { VBAR_EL1, VBAR_EL2 },
+   { CONTEXTIDR_EL1, CONTEXTIDR_EL2 },
+   { CNTKCTL_EL1, CNTHCTL_EL2 },
+};
+
 static inline u64 tcr_el2_ips_to_tcr_el1_ps(u64 tcr_el2)
 {
return ((tcr_el2 & TCR_EL2_PS_MASK) >> TCR_EL2_PS_SHIFT)
@@ -57,7 +78,27 @@ static inline u64 cptr_to_cpacr(u64 cptr_el2)
return cpacr_el1;
 }
 
-static void flush_shadow_el1_sysregs(struct kvm_vcpu *vcpu)
+static void sync_shadow_el1_sysregs(struct kvm_vcpu *vcpu)
+{
+   u64 *s_sys_regs = vcpu->arch.ctxt.shadow_sys_regs;
+   int i;
+
+   /*
+* In the virtual EL2 without VHE no EL1 system registers can't be
+* changed without trap except el1_non_trap_regs[]. So we have nothing
+* to sync on exit from a guest.
+*/
+   if (!vcpu_el2_e2h_is_set(vcpu))
+   return;
+
+   for (i = 0; i < ARRAY_SIZE(vhe_map); i++) {
+   const struct el1_el2_map *map = _map[i];
+
+   vcpu_sys_reg(vcpu, map->el2) = s_sys_regs[map->el1];
+   }
+}
+
+static void flush_shadow_el1_sysregs_nvhe(struct kvm_vcpu *vcpu)
 {
u64 *s_sys_regs = vcpu->arch.ctxt.shadow_sys_regs;
u64 tcr_el2;
@@ -86,6 +127,29 @@ static void flush_shadow_el1_sysregs(struct kvm_vcpu *vcpu)
s_sys_regs[CPACR_EL1] = cptr_to_cpacr(vcpu_sys_reg(vcpu, CPTR_EL2));
 }
 
+static void flush_shadow_el1_sysregs_vhe(struct kvm_vcpu *vcpu)
+{
+   u64 *s_sys_regs = vcpu->arch.ctxt.shadow_sys_regs;
+   int i;
+
+   /*
+* When e2h bit is set, EL2 registers becomes compatible
+* with corrensponding EL1 registers. So, no conversion required.
+*/
+   for (i = 0; i < ARRAY_SIZE(vhe_map); i++) {
+   const struct el1_el2_map *map = _map[i];
+
+   s_sys_regs[map->el1] = vcpu_sys_reg(vcpu, map->el2);
+   }
+}
+
+static void flush_shadow_el1_sysregs(struct kvm_vcpu *vcpu)
+{
+   if (vcpu_el2_e2h_is_set(vcpu))
+   flush_shadow_el1_sysregs_vhe(vcpu);
+   else
+   flush_shadow_el1_sysregs_nvhe(vcpu);
+}
 
 /*
  * List of EL0 and EL1 registers which we allow the virtual EL2 mode to access
@@ -247,6 +311,7 @@ void kvm_arm_restore_shadow_state(struct kvm_vcpu *vcpu)
if (unlikely(is_hyp_ctxt(vcpu))) {
sync_shadow_special_regs(vcpu);
sync_shadow_non_trap_el1_state(vcpu);
+   sync_shadow_el1_sysregs(vcpu);
} else
sync_special_regs(vcpu);
 }
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 32/38] KVM: arm64: Trap and emulate CPTR_EL2 accesses via CPACR_EL1 from the virtual EL2 with VHE

2017-07-18 Thread Jintack Lim
While the EL1 virtual memory control registers can be accessed in the
virtual EL2 with VHE without trap to manuplate the virtual EL2 states,
we can't do that for CPTR_EL2 for an unfortunate reason.

This is because the top bit of CPTR_EL2, which is TCPAC, will be ignored
if it is accessed via CPACR_EL1 in the virtual EL2 without trap since
the top bot of cpacr_el1 is RES0. Therefore we need to trap CPACR_EL1
accesses from the virtual EL2 to emulate this bit correctly.

Set CPTR_EL2.TCPAC bit to trap CPACR_EL1 accesses and handle them in the
existing handler considering that they could be meant to access CPTR_EL2
instead in the virtual EL2 with VHE.

Note that CPTR_EL2 format depends on HCR_EL2.E2H bit. We always keep it
in v8.0 format for the convenience. Otherwise, we need to check E2H bit
and use different bit masks in the entry.S, and we also check E2H bit in
all places we access virtual CPTR_EL2. The downside of using v8.0 format
is to convert the format when copying states between CPTR_EL2 and
CPACR_EL1 to support the virtual EL2 with VHE. The decision is subject
to change depending on the future discussion.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_emulate.h |  2 ++
 arch/arm64/kvm/context.c | 29 ++---
 arch/arm64/kvm/hyp/switch.c  |  2 ++
 arch/arm64/kvm/sys_regs.c| 18 +-
 4 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h 
b/arch/arm64/include/asm/kvm_emulate.h
index 68aafbd..4776bfc 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -59,6 +59,8 @@ enum exception_type {
 void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu);
 void kvm_arm_restore_shadow_state(struct kvm_vcpu *vcpu);
 void kvm_arm_init_cpu_context(kvm_cpu_context_t *cpu_ctxt);
+u64 cptr_to_cpacr(u64 cptr_el2);
+u64 cpacr_to_cptr(u64 cpacr_el1);
 
 static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
 {
diff --git a/arch/arm64/kvm/context.c b/arch/arm64/kvm/context.c
index 9947bc8..a7811e1 100644
--- a/arch/arm64/kvm/context.c
+++ b/arch/arm64/kvm/context.c
@@ -66,7 +66,7 @@ static inline u64 tcr_el2_ips_to_tcr_el1_ps(u64 tcr_el2)
<< TCR_IPS_SHIFT;
 }
 
-static inline u64 cptr_to_cpacr(u64 cptr_el2)
+u64 cptr_to_cpacr(u64 cptr_el2)
 {
u64 cpacr_el1 = 0;
 
@@ -78,6 +78,21 @@ static inline u64 cptr_to_cpacr(u64 cptr_el2)
return cpacr_el1;
 }
 
+u64 cpacr_to_cptr(u64 cpacr_el1)
+{
+   u64 cptr_el2;
+
+   cptr_el2 = CPTR_EL2_DEFAULT;
+   if (!(cpacr_el1 & CPACR_EL1_FPEN))
+   cptr_el2 |= CPTR_EL2_TFP;
+   if (cpacr_el1 & CPACR_EL1_TTA)
+   cptr_el2 |= CPTR_EL2_TTA;
+   if (cpacr_el1 & CPTR_EL2_TCPAC)
+   cptr_el2 |= CPTR_EL2_TCPAC;
+
+   return cptr_el2;
+}
+
 static void sync_shadow_el1_sysregs(struct kvm_vcpu *vcpu)
 {
u64 *s_sys_regs = vcpu->arch.ctxt.shadow_sys_regs;
@@ -93,8 +108,12 @@ static void sync_shadow_el1_sysregs(struct kvm_vcpu *vcpu)
 
for (i = 0; i < ARRAY_SIZE(vhe_map); i++) {
const struct el1_el2_map *map = _map[i];
+   u64 *el2_reg = _sys_reg(vcpu, map->el2);
 
-   vcpu_sys_reg(vcpu, map->el2) = s_sys_regs[map->el1];
+   /* We do trap-and-emulate CPACR_EL1 accesses. So, don't sync */
+   if (map->el2 == CPTR_EL2)
+   continue;
+   *el2_reg = s_sys_regs[map->el1];
}
 }
 
@@ -138,8 +157,12 @@ static void flush_shadow_el1_sysregs_vhe(struct kvm_vcpu 
*vcpu)
 */
for (i = 0; i < ARRAY_SIZE(vhe_map); i++) {
const struct el1_el2_map *map = _map[i];
+   u64 *el1_reg = _sys_regs[map->el1];
 
-   s_sys_regs[map->el1] = vcpu_sys_reg(vcpu, map->el2);
+   if (map->el2 == CPTR_EL2)
+   *el1_reg = cptr_to_cpacr(vcpu_sys_reg(vcpu, map->el2));
+   else
+   *el1_reg = vcpu_sys_reg(vcpu, map->el2);
}
 }
 
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index fffd0c7..50c90f2 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -50,6 +50,8 @@ static void __hyp_text __activate_traps_vhe(struct kvm_vcpu 
*vcpu)
val = read_sysreg(cpacr_el1);
val |= CPACR_EL1_TTA;
val &= ~CPACR_EL1_FPEN;
+   if (is_hyp_ctxt(vcpu))
+   val |= CPTR_EL2_TCPAC;
write_sysreg(val, cpacr_el1);
 
write_sysreg(__kvm_hyp_vector, vbar_el1);
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 2aa922c..79980be 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -972,7 +972,23 @@ static bool access_cpacr(struct kvm_vcpu *vcpu,
struct sys_reg_params *p,
const struct sys_reg_des

[RFC PATCH v2 29/38] KVM: arm64: Support a VM with VHE considering EL0 of the VHE host

2017-07-18 Thread Jintack Lim
On VHE systems, EL0 of the host kernel is considered as a part of 'VHE
host'; The execution of EL0 is affected by system registers set by the
VHE kernel including the hypervisor. To emulate this for a VM, we use
the same set of system registers (i.e. shadow registers) for the virtual
EL2 and EL0 execution.

Note that the assumption so far is that a hypervisor in a VM always runs
in the virtual EL2, and the exception level change from/to the virtual
EL2 always goes through the host hypervisor. With VHE support for a VM,
however, the exception level can be changed from EL0 to virtual EL2
without trapping to the host hypervisor. So, when returning from the VHE
host mode, set the vcpu mode depending on the physical exception level.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/context.c | 36 ++--
 1 file changed, 22 insertions(+), 14 deletions(-)

diff --git a/arch/arm64/kvm/context.c b/arch/arm64/kvm/context.c
index f3d3398..39bd92d 100644
--- a/arch/arm64/kvm/context.c
+++ b/arch/arm64/kvm/context.c
@@ -150,16 +150,18 @@ static void flush_shadow_special_regs(struct kvm_vcpu 
*vcpu)
struct kvm_cpu_context *ctxt = >arch.ctxt;
 
ctxt->hw_pstate = *vcpu_cpsr(vcpu) & ~PSR_MODE_MASK;
-   /*
-* We can emulate the guest's configuration of which
-* stack pointer to use when executing in virtual EL2 by
-* using the equivalent feature in EL1 to point to
-* either the EL1 or EL0 stack pointer.
-*/
-   if ((*vcpu_cpsr(vcpu) & PSR_MODE_MASK) == PSR_MODE_EL2h)
-   ctxt->hw_pstate |= PSR_MODE_EL1h;
-   else
-   ctxt->hw_pstate |= PSR_MODE_EL1t;
+   if (vcpu_mode_el2(vcpu)) {
+   /*
+* We can emulate the guest's configuration of which
+* stack pointer to use when executing in virtual EL2 by
+* using the equivalent feature in EL1 to point to
+* either the EL1 or EL0 stack pointer.
+*/
+   if ((*vcpu_cpsr(vcpu) & PSR_MODE_MASK) == PSR_MODE_EL2h)
+   ctxt->hw_pstate |= PSR_MODE_EL1h;
+   else
+   ctxt->hw_pstate |= PSR_MODE_EL1t;
+   }
 
ctxt->hw_sys_regs = ctxt->shadow_sys_regs;
ctxt->hw_sp_el1 = vcpu_el2_sreg(vcpu, SP_EL2);
@@ -182,8 +184,14 @@ static void sync_shadow_special_regs(struct kvm_vcpu *vcpu)
 {
struct kvm_cpu_context *ctxt = >arch.ctxt;
 
-   *vcpu_cpsr(vcpu) &= PSR_MODE_MASK;
-   *vcpu_cpsr(vcpu) |= ctxt->hw_pstate & ~PSR_MODE_MASK;
+   *vcpu_cpsr(vcpu) = ctxt->hw_pstate;
+   *vcpu_cpsr(vcpu) &= ~PSR_MODE_MASK;
+   /* Set vcpu exception level depending on the physical EL */
+   if ((ctxt->hw_pstate & PSR_MODE_MASK) == PSR_MODE_EL0t)
+   *vcpu_cpsr(vcpu) |= PSR_MODE_EL0t;
+   else
+   *vcpu_cpsr(vcpu) |= PSR_MODE_EL2h;
+
vcpu_el2_sreg(vcpu, SP_EL2) = ctxt->hw_sp_el1;
vcpu_el2_sreg(vcpu, ELR_EL2) = ctxt->hw_elr_el1;
vcpu_el2_sreg(vcpu, SPSR_EL2) = ctxt->hw_spsr_el1;
@@ -218,7 +226,7 @@ void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu)
 {
struct kvm_cpu_context *ctxt = >arch.ctxt;
 
-   if (unlikely(vcpu_mode_el2(vcpu))) {
+   if (unlikely(is_hyp_ctxt(vcpu))) {
flush_shadow_special_regs(vcpu);
flush_shadow_el1_sysregs(vcpu);
flush_shadow_non_trap_el1_state(vcpu);
@@ -236,7 +244,7 @@ void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu)
  */
 void kvm_arm_restore_shadow_state(struct kvm_vcpu *vcpu)
 {
-   if (unlikely(vcpu_mode_el2(vcpu))) {
+   if (unlikely(is_hyp_ctxt(vcpu))) {
sync_shadow_special_regs(vcpu);
sync_shadow_non_trap_el1_state(vcpu);
} else
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 27/38] KVM: arm64: Add EL2 registers defined in ARMv8.1 to vcpu context

2017-07-18 Thread Jintack Lim
ARMv8.1 added more EL2 registers: TTBR1_EL2, CONTEXTIDR_EL2, and three
EL2 virtual timer registers. Add the first two registers to vcpu context
and set their handlers. The timer registers and their handlers will be
added in a separate patch.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_host.h | 2 ++
 arch/arm64/include/asm/sysreg.h   | 2 ++
 arch/arm64/kvm/sys_regs.c | 2 ++
 3 files changed, 6 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_host.h 
b/arch/arm64/include/asm/kvm_host.h
index 53b0b33..373235c 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -151,6 +151,7 @@ enum vcpu_sysreg {
HSTR_EL2,   /* Hypervisor System Trap Register */
HACR_EL2,   /* Hypervisor Auxiliary Control Register */
TTBR0_EL2,  /* Translation Table Base Register 0 (EL2) */
+   TTBR1_EL2,  /* Translation Table Base Register 1 (EL2) */
TCR_EL2,/* Translation Control Register (EL2) */
VTTBR_EL2,  /* Virtualization Translation Table Base Register */
VTCR_EL2,   /* Virtualization Translation Control Register */
@@ -164,6 +165,7 @@ enum vcpu_sysreg {
VBAR_EL2,   /* Vector Base Address Register (EL2) */
RVBAR_EL2,  /* Reset Vector Base Address Register */
RMR_EL2,/* Reset Management Register */
+   CONTEXTIDR_EL2, /* Context ID Register (EL2) */
TPIDR_EL2,  /* EL2 Software Thread ID Register */
CNTVOFF_EL2,/* Counter-timer Virtual Offset register */
CNTHCTL_EL2,/* Counter-timer Hypervisor Control register */
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 6373d3d..b01c608 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -264,6 +264,7 @@
 #define SYS_HACR_EL2   sys_reg(3, 4, 1, 1, 7)
 
 #define SYS_TTBR0_EL2  sys_reg(3, 4, 2, 0, 0)
+#define SYS_TTBR1_EL2  sys_reg(3, 4, 2, 0, 1)
 #define SYS_TCR_EL2sys_reg(3, 4, 2, 0, 2)
 #define SYS_VTTBR_EL2  sys_reg(3, 4, 2, 1, 0)
 #define SYS_VTCR_EL2   sys_reg(3, 4, 2, 1, 2)
@@ -331,6 +332,7 @@
 #define SYS_ICH_LR14_EL2   __SYS__LR8_EL2(6)
 #define SYS_ICH_LR15_EL2   __SYS__LR8_EL2(7)
 
+#define SYS_CONTEXTIDR_EL2 sys_reg(3, 4, 13, 0, 1)
 #define SYS_TPIDR_EL2  sys_reg(3, 4, 13, 0, 2)
 
 #define SYS_CNTVOFF_EL2sys_reg(3, 4, 14, 0, 3)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index dbf5022..b3e0cb8 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1168,6 +1168,7 @@ static bool access_cpacr(struct kvm_vcpu *vcpu,
{ SYS_DESC(SYS_HACR_EL2), trap_el2_regs, reset_val, HACR_EL2, 0 },
 
{ SYS_DESC(SYS_TTBR0_EL2), trap_el2_regs, reset_val, TTBR0_EL2, 0 },
+   { SYS_DESC(SYS_TTBR1_EL2), trap_el2_regs, reset_val, TTBR1_EL2, 0 },
{ SYS_DESC(SYS_TCR_EL2), trap_el2_regs, reset_val, TCR_EL2, 0 },
{ SYS_DESC(SYS_VTTBR_EL2), trap_el2_regs, reset_val, VTTBR_EL2, 0 },
{ SYS_DESC(SYS_VTCR_EL2), trap_el2_regs, reset_val, VTCR_EL2, 0 },
@@ -1194,6 +1195,7 @@ static bool access_cpacr(struct kvm_vcpu *vcpu,
{ SYS_DESC(SYS_RVBAR_EL2), trap_el2_regs, reset_val, RVBAR_EL2, 0 },
{ SYS_DESC(SYS_RMR_EL2), trap_el2_regs, reset_val, RMR_EL2, 0 },
 
+   { SYS_DESC(SYS_CONTEXTIDR_EL2), trap_el2_regs, reset_val, 
CONTEXTIDR_EL2, 0 },
{ SYS_DESC(SYS_TPIDR_EL2), trap_el2_regs, reset_val, TPIDR_EL2, 0 },
 
{ SYS_DESC(SYS_CNTVOFF_EL2), trap_el2_regs, reset_val, CNTVOFF_EL2, 0 },
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 22/38] KVM: arm64: Handle PSCI call via smc from the guest

2017-07-18 Thread Jintack Lim
VMs used to execute hvc #0 for the psci call if EL3 is not implemented.
However, when we come to provide the virtual EL2 mode to the VM, the
host OS inside the VM calls kvm_call_hyp() which is also hvc #0. So,
it's hard to differentiate between them from the host hypervisor's point
of view.

So, let the VM execute smc instruction for the psci call. On ARMv8.3,
even if EL3 is not implemented, a smc instruction executed at non-secure
EL1 is trapped to EL2 if HCR_EL2.TSC==1, rather than being treated as
UNDEFINED. So, the host hypervisor can handle this psci call without any
confusion.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/handle_exit.c | 24 ++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index d19e253..6cf6b93 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -53,8 +53,28 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run 
*run)
 
 static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
-   kvm_inject_undefined(vcpu);
-   return 1;
+   int ret;
+
+   /* If imm is non-zero, it's not defined */
+   if (kvm_vcpu_hvc_get_imm(vcpu)) {
+   kvm_inject_undefined(vcpu);
+   return 1;
+   }
+
+   /*
+* If imm is zero, it's a psci call.
+* Note that on ARMv8.3, even if EL3 is not implemented, SMC executed
+* at Non-secure EL1 is trapped to EL2 if HCR_EL2.TSC==1, rather than
+* being treated as UNDEFINED.
+*/
+   ret = kvm_psci_call(vcpu);
+   if (ret < 0) {
+   kvm_inject_undefined(vcpu);
+   return 1;
+   }
+   kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+
+   return ret;
 }
 
 /*
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 26/38] KVM: arm64: Add macros to support the virtual EL2 with VHE

2017-07-18 Thread Jintack Lim
These macros will be used to support the virtual EL2 with VHE.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_emulate.h | 24 
 1 file changed, 24 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_emulate.h 
b/arch/arm64/include/asm/kvm_emulate.h
index 3017234..68aafbd 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -173,6 +173,30 @@ static inline bool vcpu_mode_el2(const struct kvm_vcpu 
*vcpu)
return mode == PSR_MODE_EL2h || mode == PSR_MODE_EL2t;
 }
 
+static inline bool vcpu_el2_e2h_is_set(const struct kvm_vcpu *vcpu)
+{
+   return (vcpu_sys_reg(vcpu, HCR_EL2) & HCR_E2H);
+}
+
+static inline bool vcpu_el2_tge_is_set(const struct kvm_vcpu *vcpu)
+{
+   return (vcpu_sys_reg(vcpu, HCR_EL2) & HCR_TGE);
+}
+
+static inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu)
+{
+   /*
+* We are in a hypervisor context if the vcpu mode is EL2 or
+* E2H and TGE bits are set. The latter means we are in the user space
+* of the VHE kernel. ARMv8.1 ARM describes this as 'InHost'
+*/
+   if (vcpu_mode_el2(vcpu) ||
+   (vcpu_el2_e2h_is_set(vcpu) && vcpu_el2_tge_is_set(vcpu)))
+   return true;
+
+   return false;
+}
+
 static inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu)
 {
return vcpu->arch.fault.esr_el2;
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 25/38] KVM: arm64: Respect virtual CPTR_EL2.TFP setting

2017-07-18 Thread Jintack Lim
Forward traps due to FP/ASIMD register accesses to the virtual EL2 if
virtual CPTR_EL2.TFP is set. Note that if TFP bit is set, then even
accesses to FP/ASIMD register from EL2 as well as NS EL0/1 will trap to
EL2. So, we don't check the VM's exception level.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kernel/asm-offsets.c |  1 +
 arch/arm64/kvm/handle_exit.c| 15 +++
 arch/arm64/kvm/hyp/entry.S  | 13 +
 arch/arm64/kvm/hyp/hyp-entry.S  |  2 +-
 4 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index b3bb7ef..f5117a3 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -134,6 +134,7 @@ int main(void)
   DEFINE(CPU_FP_REGS,  offsetof(struct kvm_regs, fp_regs));
   DEFINE(VCPU_FPEXC32_EL2, offsetof(struct kvm_vcpu, 
arch.ctxt.sys_regs[FPEXC32_EL2]));
   DEFINE(VCPU_HOST_CONTEXT,offsetof(struct kvm_vcpu, 
arch.host_cpu_context));
+  DEFINE(VIRTUAL_CPTR_EL2, offsetof(struct kvm_vcpu, 
arch.ctxt.sys_regs[CPTR_EL2]));
 #endif
 #ifdef CONFIG_CPU_PM
   DEFINE(CPU_SUSPEND_SZ,   sizeof(struct cpu_suspend_ctx));
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 25ec824..d4e7b2b 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -84,11 +84,18 @@ static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run 
*run)
 }
 
 /*
- * Guest access to FP/ASIMD registers are routed to this handler only
- * when the system doesn't support FP/ASIMD.
+ * When the system supports FP/ASMID and we are NOT running nested
+ * virtualization, FP/ASMID traps are handled in EL2 directly.
+ * This handler handles the cases those are not belong to the above case.
  */
-static int handle_no_fpsimd(struct kvm_vcpu *vcpu, struct kvm_run *run)
+static int kvm_handle_fpasimd(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
+
+   /* This is for nested virtualization */
+   if (vcpu_sys_reg(vcpu, CPTR_EL2) & CPTR_EL2_TFP)
+   return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
+
+   /* This is the case when the system doesn't support FP/ASIMD. */
kvm_inject_undefined(vcpu);
return 1;
 }
@@ -220,7 +227,7 @@ static int kvm_handle_eret(struct kvm_vcpu *vcpu, struct 
kvm_run *run)
[ESR_ELx_EC_BREAKPT_LOW]= kvm_handle_guest_debug,
[ESR_ELx_EC_BKPT32] = kvm_handle_guest_debug,
[ESR_ELx_EC_BRK64]  = kvm_handle_guest_debug,
-   [ESR_ELx_EC_FP_ASIMD]   = handle_no_fpsimd,
+   [ESR_ELx_EC_FP_ASIMD]   = kvm_handle_fpasimd,
 };
 
 static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
index 12ee62d..95af673 100644
--- a/arch/arm64/kvm/hyp/entry.S
+++ b/arch/arm64/kvm/hyp/entry.S
@@ -158,6 +158,19 @@ abort_guest_exit_end:
 1: ret
 ENDPROC(__guest_exit)
 
+ENTRY(__fpsimd_guest_trap)
+   // If virtual CPTR_EL2.TFP is set, then forward the trap to the
+   // virtual EL2. For the non-nested case, this bit is always 0.
+   mrs x1, tpidr_el2
+   ldr x0, [x1, #VIRTUAL_CPTR_EL2]
+   and x0, x0, #CPTR_EL2_TFP
+   cbnzx0, 1f
+   b   __fpsimd_guest_restore
+1:
+   mov x0, #ARM_EXCEPTION_TRAP
+   b   __guest_exit
+ENDPROC(__fpsimd_guest_trap)
+
 ENTRY(__fpsimd_guest_restore)
stp x2, x3, [sp, #-16]!
stp x4, lr, [sp, #-16]!
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index 5170ce1..ab169fd 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -113,7 +113,7 @@ el1_trap:
 */
 alternative_if_not ARM64_HAS_NO_FPSIMD
cmp x0, #ESR_ELx_EC_FP_ASIMD
-   b.eq__fpsimd_guest_restore
+   b.eq__fpsimd_guest_trap
 alternative_else_nop_endif
 
mrs x1, tpidr_el2
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 28/38] KVM: arm64: Emulate EL12 register accesses from the virtual EL2

2017-07-18 Thread Jintack Lim
With HCR_EL2.NV bit set, accesses to EL12 registers in the virtual EL2
trap to EL2. Handle those traps just like we do for EL1 registers.

One exception is CNTKCTL_EL12. We don't trap on CNTKCTL_EL1 for non-VHE
virtual EL2 because we don't have to. However, accessing CNTKCTL_EL12
will trap since it's one of the EL12 registers controlled by HCR_EL2.NV
bit.  Therefore, add a handler for it and don't treat it as a
non-trap-registers when preparing a shadow context.

Move EL12 system register macros to a common place to reuse them.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_hyp.h | 24 
 arch/arm64/include/asm/sysreg.h  | 24 
 arch/arm64/kvm/context.c |  7 +++
 arch/arm64/kvm/sys_regs.c| 25 +
 4 files changed, 56 insertions(+), 24 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 4572a9b..353b895 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -73,30 +73,6 @@
 #define read_sysreg_el1(r) read_sysreg_elx(r, _EL1, _EL12)
 #define write_sysreg_el1(v,r)  write_sysreg_elx(v, r, _EL1, _EL12)
 
-/* The VHE specific system registers and their encoding */
-#define sctlr_EL12  sys_reg(3, 5, 1, 0, 0)
-#define cpacr_EL12  sys_reg(3, 5, 1, 0, 2)
-#define ttbr0_EL12  sys_reg(3, 5, 2, 0, 0)
-#define ttbr1_EL12  sys_reg(3, 5, 2, 0, 1)
-#define tcr_EL12sys_reg(3, 5, 2, 0, 2)
-#define afsr0_EL12  sys_reg(3, 5, 5, 1, 0)
-#define afsr1_EL12  sys_reg(3, 5, 5, 1, 1)
-#define esr_EL12sys_reg(3, 5, 5, 2, 0)
-#define far_EL12sys_reg(3, 5, 6, 0, 0)
-#define mair_EL12   sys_reg(3, 5, 10, 2, 0)
-#define amair_EL12  sys_reg(3, 5, 10, 3, 0)
-#define vbar_EL12   sys_reg(3, 5, 12, 0, 0)
-#define contextidr_EL12 sys_reg(3, 5, 13, 0, 1)
-#define cntkctl_EL12sys_reg(3, 5, 14, 1, 0)
-#define cntp_tval_EL02  sys_reg(3, 5, 14, 2, 0)
-#define cntp_ctl_EL02   sys_reg(3, 5, 14, 2, 1)
-#define cntp_cval_EL02  sys_reg(3, 5, 14, 2, 2)
-#define cntv_tval_EL02  sys_reg(3, 5, 14, 3, 0)
-#define cntv_ctl_EL02   sys_reg(3, 5, 14, 3, 1)
-#define cntv_cval_EL02  sys_reg(3, 5, 14, 3, 2)
-#define spsr_EL12   sys_reg(3, 5, 4, 0, 0)
-#define elr_EL12sys_reg(3, 5, 4, 0, 1)
-
 /**
  * hyp_alternate_select - Generates patchable code sequences that are
  * used to switch between two implementations of a function, depending
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index b01c608..b8d4d0c 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -338,6 +338,30 @@
 #define SYS_CNTVOFF_EL2sys_reg(3, 4, 14, 0, 3)
 #define SYS_CNTHCTL_EL2sys_reg(3, 4, 14, 1, 0)
 
+/* The VHE specific system registers and their encoding */
+#define sctlr_EL12  sys_reg(3, 5, 1, 0, 0)
+#define cpacr_EL12  sys_reg(3, 5, 1, 0, 2)
+#define ttbr0_EL12  sys_reg(3, 5, 2, 0, 0)
+#define ttbr1_EL12  sys_reg(3, 5, 2, 0, 1)
+#define tcr_EL12sys_reg(3, 5, 2, 0, 2)
+#define afsr0_EL12  sys_reg(3, 5, 5, 1, 0)
+#define afsr1_EL12  sys_reg(3, 5, 5, 1, 1)
+#define esr_EL12sys_reg(3, 5, 5, 2, 0)
+#define far_EL12sys_reg(3, 5, 6, 0, 0)
+#define mair_EL12   sys_reg(3, 5, 10, 2, 0)
+#define amair_EL12  sys_reg(3, 5, 10, 3, 0)
+#define vbar_EL12   sys_reg(3, 5, 12, 0, 0)
+#define contextidr_EL12 sys_reg(3, 5, 13, 0, 1)
+#define cntkctl_EL12sys_reg(3, 5, 14, 1, 0)
+#define cntp_tval_EL02  sys_reg(3, 5, 14, 2, 0)
+#define cntp_ctl_EL02   sys_reg(3, 5, 14, 2, 1)
+#define cntp_cval_EL02  sys_reg(3, 5, 14, 2, 2)
+#define cntv_tval_EL02  sys_reg(3, 5, 14, 3, 0)
+#define cntv_ctl_EL02   sys_reg(3, 5, 14, 3, 1)
+#define cntv_cval_EL02  sys_reg(3, 5, 14, 3, 2)
+#define spsr_EL12   sys_reg(3, 5, 4, 0, 0)
+#define elr_EL12sys_reg(3, 5, 4, 0, 1)
+
 #define SYS_SP_EL2 sys_reg(3, 6, 4, 1, 0)
 
 /* Common SCTLR_ELx flags. */
diff --git a/arch/arm64/kvm/context.c b/arch/arm64/kvm/context.c
index e1bc753..f3d3398 100644
--- a/arch/arm64/kvm/context.c
+++ b/arch/arm64/kvm/context.c
@@ -121,6 +121,13 @@ static void copy_shadow_non_trap_el1_state(struct kvm_vcpu 
*vcpu, bool setup)
for (i = 0; i < ARRAY_SIZE(el1_non_trap_regs); i++) {
const int sr = el1_non_trap_regs[i];
 
+   /*
+* We trap on cntkctl_el12 accesses from virtual EL2 as suppose
+* to not trapping on cntlctl_el1

[RFC PATCH v2 20/38] KVM: arm64: Handle eret instruction traps

2017-07-18 Thread Jintack Lim
When HCR.NV bit is set, eret instructions trap to EL2 with EC code 0x1A.
Emulate eret instructions by setting pc and pstate.

Note that the current exception level is always the virtual EL2, since
we set HCR_EL2.NV bit only when entering the virtual EL2. So, we take
spsr and elr states from the virtual _EL2 registers.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/esr.h |  1 +
 arch/arm64/kvm/handle_exit.c | 16 
 arch/arm64/kvm/trace.h   | 21 +
 3 files changed, 38 insertions(+)

diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index e7d8e28..210fde6 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -43,6 +43,7 @@
 #define ESR_ELx_EC_HVC64   (0x16)
 #define ESR_ELx_EC_SMC64   (0x17)
 #define ESR_ELx_EC_SYS64   (0x18)
+#define ESR_ELx_EC_ERET(0x1A)
 /* Unallocated EC: 0x19 - 0x1E */
 #define ESR_ELx_EC_IMP_DEF (0x1f)
 #define ESR_ELx_EC_IABT_LOW(0x20)
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 17d8a16..9259881 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -147,6 +147,21 @@ static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu, 
struct kvm_run *run)
return 1;
 }
 
+static int kvm_handle_eret(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+   trace_kvm_nested_eret(vcpu, vcpu_el2_sreg(vcpu, ELR_EL2),
+ vcpu_el2_sreg(vcpu, SPSR_EL2));
+
+   /*
+* Note that the current exception level is always the virtual EL2,
+* since we set HCR_EL2.NV bit only when entering the virtual EL2.
+*/
+   *vcpu_pc(vcpu) = vcpu_el2_sreg(vcpu, ELR_EL2);
+   *vcpu_cpsr(vcpu) = vcpu_el2_sreg(vcpu, SPSR_EL2);
+
+   return 1;
+}
+
 static exit_handle_fn arm_exit_handlers[] = {
[0 ... ESR_ELx_EC_MAX]  = kvm_handle_unknown_ec,
[ESR_ELx_EC_WFx]= kvm_handle_wfx,
@@ -160,6 +175,7 @@ static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu, 
struct kvm_run *run)
[ESR_ELx_EC_HVC64]  = handle_hvc,
[ESR_ELx_EC_SMC64]  = handle_smc,
[ESR_ELx_EC_SYS64]  = kvm_handle_sys_reg,
+   [ESR_ELx_EC_ERET]   = kvm_handle_eret,
[ESR_ELx_EC_IABT_LOW]   = kvm_handle_guest_abort,
[ESR_ELx_EC_DABT_LOW]   = kvm_handle_guest_abort,
[ESR_ELx_EC_SOFTSTP_LOW]= kvm_handle_guest_debug,
diff --git a/arch/arm64/kvm/trace.h b/arch/arm64/kvm/trace.h
index 7c86cfb..5f40987 100644
--- a/arch/arm64/kvm/trace.h
+++ b/arch/arm64/kvm/trace.h
@@ -187,6 +187,27 @@
TP_printk("vcpu: %p, inject exception to vEL2: ESR_EL2 0x%lx, vector: 
0x%016lx",
  __entry->vcpu, __entry->esr_el2, __entry->pc)
 );
+
+TRACE_EVENT(kvm_nested_eret,
+   TP_PROTO(struct kvm_vcpu *vcpu, unsigned long elr_el2,
+unsigned long spsr_el2),
+   TP_ARGS(vcpu, elr_el2, spsr_el2),
+
+   TP_STRUCT__entry(
+   __field(struct kvm_vcpu *,  vcpu)
+   __field(unsigned long,  elr_el2)
+   __field(unsigned long,  spsr_el2)
+   ),
+
+   TP_fast_assign(
+   __entry->vcpu = vcpu;
+   __entry->elr_el2 = elr_el2;
+   __entry->spsr_el2 = spsr_el2;
+   ),
+
+   TP_printk("vcpu: %p, eret to elr_el2: 0x%016lx, with spsr_el2: 0x%08lx",
+ __entry->vcpu, __entry->elr_el2, __entry->spsr_el2)
+);
 #endif /* _TRACE_ARM64_KVM_H */
 
 #undef TRACE_INCLUDE_PATH
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 17/38] KVM: arm64: Trap EL1 VM register accesses in virtual EL2

2017-07-18 Thread Jintack Lim
From: Christoffer Dall 

When running in virtual EL2 mode, we actually run the hardware in EL1
and therefore have to use the EL1 registers to ensure correct operation.

By setting the HCR.TVM and HCR.TVRM we ensure that the virtual EL2 mode
doesn't shoot itself in the foot when setting up what it believes to be
a different mode's system register state (for example when preparing to
switch to a VM).

We can leverage the existing sysregs infrastructure to support trapped
accesses to these registers.

Signed-off-by: Christoffer Dall 
---
 arch/arm64/kvm/hyp/switch.c | 2 ++
 arch/arm64/kvm/sys_regs.c   | 7 ++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 945e79c..ec91cd08 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -85,6 +85,8 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
write_sysreg(1 << 30, fpexc32_el2);
isb();
}
+   if (vcpu_mode_el2(vcpu))
+   val |= HCR_TVM | HCR_TRVM;
write_sysreg(val, hcr_el2);
/* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
write_sysreg(1 << 15, hstr_el2);
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 2b3ed70..d8b1d4b 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -121,7 +121,12 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
 {
bool was_enabled = vcpu_has_cache_enabled(vcpu);
 
-   BUG_ON(!p->is_write);
+   BUG_ON(!vcpu_mode_el2(vcpu) && !p->is_write);
+
+   if (!p->is_write) {
+   p->regval = vcpu_sys_reg(vcpu, r->reg);
+   return true;
+   }
 
if (!p->is_aarch32) {
vcpu_sys_reg(vcpu, r->reg) = p->regval;
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 12/38] arm64: Add missing TCR hw defines

2017-07-18 Thread Jintack Lim
From: Christoffer Dall 

Some bits of the TCR weren't defined and since we're about to use these
in KVM, add these defines.

Signed-off-by: Christoffer Dall 
---
 arch/arm64/include/asm/pgtable-hwdef.h | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm64/include/asm/pgtable-hwdef.h 
b/arch/arm64/include/asm/pgtable-hwdef.h
index eb0c2bd..d26cab7 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -272,9 +272,15 @@
 #define TCR_TG1_4K (UL(2) << TCR_TG1_SHIFT)
 #define TCR_TG1_64K(UL(3) << TCR_TG1_SHIFT)
 
+#define TCR_IPS_SHIFT  32
+#define TCR_IPS_MASK   (UL(7) << TCR_IPS_SHIFT)
+
 #define TCR_ASID16 (UL(1) << 36)
 #define TCR_TBI0   (UL(1) << 37)
 #define TCR_HA (UL(1) << 39)
 #define TCR_HD (UL(1) << 40)
 
+#define TCR_EPD1   (UL(1) << 23)
+#define TCR_EPD0   (UL(1) << 7)
+
 #endif
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 21/38] KVM: arm64: Set a handler for the system instruction traps

2017-07-18 Thread Jintack Lim
When HCR.NV bit is set, execution of the EL2 translation regime address
aranslation instructions and TLB maintenance instructions are trapped to
EL2. In addition, execution of the EL1 translation regime address
aranslation instructions and TLB maintenance instructions that are only
accessible from EL2 and above are trapped to EL2. In these cases,
ESR_EL2.EC will be set to 0x18.

Change the existing handler to handle those system instructions as well
as MRS/MSR instructions.  Emulation of each system instructions will be
done in separate patches.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_coproc.h |  2 +-
 arch/arm64/kvm/handle_exit.c|  2 +-
 arch/arm64/kvm/sys_regs.c   | 53 -
 arch/arm64/kvm/trace.h  |  2 +-
 4 files changed, 50 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_coproc.h 
b/arch/arm64/include/asm/kvm_coproc.h
index 0b52377..1b3d21b 100644
--- a/arch/arm64/include/asm/kvm_coproc.h
+++ b/arch/arm64/include/asm/kvm_coproc.h
@@ -43,7 +43,7 @@ void kvm_register_target_sys_reg_table(unsigned int target,
 int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
 int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
 int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
-int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_sys(struct kvm_vcpu *vcpu, struct kvm_run *run);
 
 #define kvm_coproc_table_init kvm_sys_reg_table_init
 void kvm_sys_reg_table_init(void);
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 9259881..d19e253 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -174,7 +174,7 @@ static int kvm_handle_eret(struct kvm_vcpu *vcpu, struct 
kvm_run *run)
[ESR_ELx_EC_SMC32]  = handle_smc,
[ESR_ELx_EC_HVC64]  = handle_hvc,
[ESR_ELx_EC_SMC64]  = handle_smc,
-   [ESR_ELx_EC_SYS64]  = kvm_handle_sys_reg,
+   [ESR_ELx_EC_SYS64]  = kvm_handle_sys,
[ESR_ELx_EC_ERET]   = kvm_handle_eret,
[ESR_ELx_EC_IABT_LOW]   = kvm_handle_guest_abort,
[ESR_ELx_EC_DABT_LOW]   = kvm_handle_guest_abort,
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 7062645..dbf5022 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1808,6 +1808,40 @@ static int emulate_sys_reg(struct kvm_vcpu *vcpu,
return 1;
 }
 
+static int emulate_tlbi(struct kvm_vcpu *vcpu,
+struct sys_reg_params *params)
+{
+   /* TODO: support tlbi instruction emulation*/
+   kvm_inject_undefined(vcpu);
+   return 1;
+}
+
+static int emulate_at(struct kvm_vcpu *vcpu,
+struct sys_reg_params *params)
+{
+   /* TODO: support address translation instruction emulation */
+   kvm_inject_undefined(vcpu);
+   return 1;
+}
+
+static int emulate_sys_instr(struct kvm_vcpu *vcpu,
+struct sys_reg_params *params)
+{
+   int ret = 0;
+
+   /* TLB maintenance instructions*/
+   if (params->CRn == 0b1000)
+   ret = emulate_tlbi(vcpu, params);
+   /* Address Translation instructions */
+   else if (params->CRn == 0b0111 && params->CRm == 0b1000)
+   ret = emulate_at(vcpu, params);
+
+   if (ret)
+   kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+
+   return ret;
+}
+
 static void reset_sys_reg_descs(struct kvm_vcpu *vcpu,
  const struct sys_reg_desc *table, size_t num)
 {
@@ -1819,18 +1853,19 @@ static void reset_sys_reg_descs(struct kvm_vcpu *vcpu,
 }
 
 /**
- * kvm_handle_sys_reg -- handles a mrs/msr trap on a guest sys_reg access
+ * kvm_handle_sys-- handles a system instruction or mrs/msr instruction trap
+   on a guest execution
  * @vcpu: The VCPU pointer
  * @run:  The kvm_run struct
  */
-int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run)
+int kvm_handle_sys(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
struct sys_reg_params params;
unsigned long esr = kvm_vcpu_get_hsr(vcpu);
int Rt = kvm_vcpu_sys_get_rt(vcpu);
int ret;
 
-   trace_kvm_handle_sys_reg(esr);
+   trace_kvm_handle_sys(esr);
 
params.is_aarch32 = false;
params.is_32bit = false;
@@ -1842,10 +1877,16 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct 
kvm_run *run)
params.regval = vcpu_get_reg(vcpu, Rt);
params.is_write = !(esr & 1);
 
-   ret = emulate_sys_reg(vcpu, );
+   if (params.Op0 == 1) {
+   /* System instructions */
+   ret = emulate_sys_instr(vcpu, );
+   } else {
+   /* MRS/MSR instructions */
+   ret = emulate_sys_reg(vcpu, );
+   if (!params.is_write)
+   vcpu_set_

[RFC PATCH v2 18/38] KVM: arm64: Trap SPSR_EL1, ELR_EL1 and VBAR_EL1 from virtual EL2

2017-07-18 Thread Jintack Lim
For the same reason we trap virtual memory register accesses at virtual
EL2, we need to trap SPSR_EL1, ELR_EL1 and VBAR_EL1 accesses. ARM v8.3
introduces the HCR_EL2.NV1 bit to be able to trap on those register
accesses in EL1. Do not set this bit until the whole nesting support is
completed.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/sysreg.h |  2 ++
 arch/arm64/kvm/sys_regs.c   | 29 -
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 98c32ef..6373d3d 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -164,6 +164,8 @@
 #define SYS_TTBR1_EL1  sys_reg(3, 0, 2, 0, 1)
 #define SYS_TCR_EL1sys_reg(3, 0, 2, 0, 2)
 
+#defineSYS_SPSR_EL1sys_reg(3, 0, 4, 0, 0)
+#defineSYS_ELR_EL1 sys_reg(3, 0, 4, 0, 1)
 #define SYS_ICC_PMR_EL1sys_reg(3, 0, 4, 6, 0)
 
 #define SYS_AFSR0_EL1  sys_reg(3, 0, 5, 1, 0)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index d8b1d4b..b83fef2 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -936,6 +936,30 @@ static bool trap_el2_regs(struct kvm_vcpu *vcpu,
return true;
 }
 
+static bool access_elr(struct kvm_vcpu *vcpu,
+   struct sys_reg_params *p,
+   const struct sys_reg_desc *r)
+{
+   access_rw(p, >arch.ctxt.gp_regs.elr_el1);
+   return true;
+}
+
+static bool access_spsr(struct kvm_vcpu *vcpu,
+   struct sys_reg_params *p,
+   const struct sys_reg_desc *r)
+{
+   access_rw(p, >arch.ctxt.gp_regs.spsr[KVM_SPSR_EL1]);
+   return true;
+}
+
+static bool access_vbar(struct kvm_vcpu *vcpu,
+   struct sys_reg_params *p,
+   const struct sys_reg_desc *r)
+{
+   access_rw(p, _sys_reg(vcpu, r->reg));
+   return true;
+}
+
 /*
  * Architected system registers.
  * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
@@ -994,6 +1018,9 @@ static bool trap_el2_regs(struct kvm_vcpu *vcpu,
{ SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 },
{ SYS_DESC(SYS_TCR_EL1), access_vm_reg, reset_val, TCR_EL1, 0 },
 
+   { SYS_DESC(SYS_SPSR_EL1), access_spsr},
+   { SYS_DESC(SYS_ELR_EL1), access_elr},
+
{ SYS_DESC(SYS_AFSR0_EL1), access_vm_reg, reset_unknown, AFSR0_EL1 },
{ SYS_DESC(SYS_AFSR1_EL1), access_vm_reg, reset_unknown, AFSR1_EL1 },
{ SYS_DESC(SYS_ESR_EL1), access_vm_reg, reset_unknown, ESR_EL1 },
@@ -1006,7 +1033,7 @@ static bool trap_el2_regs(struct kvm_vcpu *vcpu,
{ SYS_DESC(SYS_MAIR_EL1), access_vm_reg, reset_unknown, MAIR_EL1 },
{ SYS_DESC(SYS_AMAIR_EL1), access_vm_reg, reset_amair_el1, AMAIR_EL1 },
 
-   { SYS_DESC(SYS_VBAR_EL1), NULL, reset_val, VBAR_EL1, 0 },
+   { SYS_DESC(SYS_VBAR_EL1), access_vbar, reset_val, VBAR_EL1, 0 },
 
{ SYS_DESC(SYS_ICC_IAR0_EL1), write_to_read_only },
{ SYS_DESC(SYS_ICC_EOIR0_EL1), read_from_write_only },
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 16/38] KVM: arm64: Support to inject exceptions to the virtual EL2

2017-07-18 Thread Jintack Lim
Support inject synchronous exceptions to the virtual EL2 as
described in ARM ARM AArch64.TakeException().

This can be easily extended to support to inject asynchronous exceptions
to the virtual EL2, but it will be added in a later patch when appropriate.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm/include/asm/kvm_emulate.h   |  7 +++
 arch/arm64/include/asm/kvm_emulate.h |  2 +
 arch/arm64/kvm/Makefile  |  1 +
 arch/arm64/kvm/emulate-nested.c  | 83 
 arch/arm64/kvm/trace.h   | 20 +
 5 files changed, 113 insertions(+)
 create mode 100644 arch/arm64/kvm/emulate-nested.c

diff --git a/arch/arm/include/asm/kvm_emulate.h 
b/arch/arm/include/asm/kvm_emulate.h
index 0a03b7d..29a4dec 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -47,6 +47,13 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 
reg_num,
 void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
 void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
 
+static inline int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2)
+{
+   kvm_err("Unexpected call to %s for the non-nesting configuration\n",
+__func__);
+   return -EINVAL;
+}
+
 static inline void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu) { };
 static inline void kvm_arm_restore_shadow_state(struct kvm_vcpu *vcpu) { };
 static inline void kvm_arm_init_cpu_context(kvm_cpu_context_t *cpu_ctxt) { };
diff --git a/arch/arm64/include/asm/kvm_emulate.h 
b/arch/arm64/include/asm/kvm_emulate.h
index 94f98cc..3017234 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -54,6 +54,8 @@ enum exception_type {
 void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
 void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
 
+int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2);
+
 void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu);
 void kvm_arm_restore_shadow_state(struct kvm_vcpu *vcpu);
 void kvm_arm_init_cpu_context(kvm_cpu_context_t *cpu_ctxt);
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 5762337..0263ef0 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -37,3 +37,4 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
 kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
 
 kvm-$(CONFIG_KVM_ARM_HOST) += nested.o
+kvm-$(CONFIG_KVM_ARM_HOST) += emulate-nested.o
diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
new file mode 100644
index 000..48b84cc
--- /dev/null
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2016 - Linaro and Columbia University
+ * Author: Jintack Lim <jintack@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include 
+#include 
+
+#include 
+
+#include "trace.h"
+
+/* This is borrowed from get_except_vector in inject_fault.c */
+static u64 get_el2_except_vector(struct kvm_vcpu *vcpu,
+   enum exception_type type)
+{
+   u64 exc_offset;
+
+   switch (*vcpu_cpsr(vcpu) & (PSR_MODE_MASK | PSR_MODE32_BIT)) {
+   case PSR_MODE_EL2t:
+   exc_offset = CURRENT_EL_SP_EL0_VECTOR;
+   break;
+   case PSR_MODE_EL2h:
+   exc_offset = CURRENT_EL_SP_ELx_VECTOR;
+   break;
+   case PSR_MODE_EL1t:
+   case PSR_MODE_EL1h:
+   case PSR_MODE_EL0t:
+   exc_offset = LOWER_EL_AArch64_VECTOR;
+   break;
+   default:
+   kvm_err("Unexpected previous exception level: aarch32\n");
+   exc_offset = LOWER_EL_AArch32_VECTOR;
+   }
+
+   return vcpu_sys_reg(vcpu, VBAR_EL2) + exc_offset + type;
+}
+
+/*
+ * Emulate taking an exception to EL2.
+ * See ARM ARM J8.1.2 AArch64.TakeException()
+ */
+static int kvm_inject_nested(struct kvm_vcpu *vcpu, u64 esr_el2,
+enum exception_type type)
+{
+   int ret = 1;
+
+   if (!nested_virt_in_use(vcpu)) {
+   kvm_err("Unexpected call to %s for the non-nesting 
configuration\n",
+   __func__);
+   return -EINVAL;
+   }
+
+   vcpu_el2_sreg(vcpu, SPSR_EL2) = *vcpu_cpsr(vcpu);
+   vcpu_el2_sreg(vcpu, ELR_EL2) = *vcpu_pc(vcpu);
+   

[RFC PATCH v2 11/38] KVM: arm64: Set vcpu context depending on the guest exception level

2017-07-18 Thread Jintack Lim
If the guest exception level is EL2, then set up the shadow context of
the virtual EL2 to hardware. Otherwise, set the regular EL0/EL1 context.

Note that the shadow context content will be prepared in subsequent
patches.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/context.c | 74 +---
 1 file changed, 64 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/kvm/context.c b/arch/arm64/kvm/context.c
index bc43e66..2645787 100644
--- a/arch/arm64/kvm/context.c
+++ b/arch/arm64/kvm/context.c
@@ -18,11 +18,29 @@
 #include 
 #include 
 
-/**
- * kvm_arm_setup_shadow_state -- prepare shadow state based on emulated mode
- * @vcpu: The VCPU pointer
- */
-void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu)
+static void flush_shadow_special_regs(struct kvm_vcpu *vcpu)
+{
+   struct kvm_cpu_context *ctxt = >arch.ctxt;
+
+   ctxt->hw_pstate = *vcpu_cpsr(vcpu) & ~PSR_MODE_MASK;
+   /*
+* We can emulate the guest's configuration of which
+* stack pointer to use when executing in virtual EL2 by
+* using the equivalent feature in EL1 to point to
+* either the EL1 or EL0 stack pointer.
+*/
+   if ((*vcpu_cpsr(vcpu) & PSR_MODE_MASK) == PSR_MODE_EL2h)
+   ctxt->hw_pstate |= PSR_MODE_EL1h;
+   else
+   ctxt->hw_pstate |= PSR_MODE_EL1t;
+
+   ctxt->hw_sys_regs = ctxt->shadow_sys_regs;
+   ctxt->hw_sp_el1 = vcpu_el2_sreg(vcpu, SP_EL2);
+   ctxt->hw_elr_el1 = vcpu_el2_sreg(vcpu, ELR_EL2);
+   ctxt->hw_spsr_el1 = vcpu_el2_sreg(vcpu, SPSR_EL2);
+}
+
+static void flush_special_regs(struct kvm_vcpu *vcpu)
 {
struct kvm_cpu_context *ctxt = >arch.ctxt;
 
@@ -33,11 +51,18 @@ void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu)
ctxt->hw_spsr_el1 = ctxt->gp_regs.spsr[KVM_SPSR_EL1];
 }
 
-/**
- * kvm_arm_restore_shadow_state -- write back shadow state from guest
- * @vcpu: The VCPU pointer
- */
-void kvm_arm_restore_shadow_state(struct kvm_vcpu *vcpu)
+static void sync_shadow_special_regs(struct kvm_vcpu *vcpu)
+{
+   struct kvm_cpu_context *ctxt = >arch.ctxt;
+
+   *vcpu_cpsr(vcpu) &= PSR_MODE_MASK;
+   *vcpu_cpsr(vcpu) |= ctxt->hw_pstate & ~PSR_MODE_MASK;
+   vcpu_el2_sreg(vcpu, SP_EL2) = ctxt->hw_sp_el1;
+   vcpu_el2_sreg(vcpu, ELR_EL2) = ctxt->hw_elr_el1;
+   vcpu_el2_sreg(vcpu, SPSR_EL2) = ctxt->hw_spsr_el1;
+}
+
+static void sync_special_regs(struct kvm_vcpu *vcpu)
 {
struct kvm_cpu_context *ctxt = >arch.ctxt;
 
@@ -47,6 +72,35 @@ void kvm_arm_restore_shadow_state(struct kvm_vcpu *vcpu)
ctxt->gp_regs.spsr[KVM_SPSR_EL1] = ctxt->hw_spsr_el1;
 }
 
+/**
+ * kvm_arm_setup_shadow_state -- prepare shadow state based on emulated mode
+ * @vcpu: The VCPU pointer
+ */
+void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu)
+{
+   struct kvm_cpu_context *ctxt = >arch.ctxt;
+
+   if (unlikely(vcpu_mode_el2(vcpu))) {
+   flush_shadow_special_regs(vcpu);
+   ctxt->hw_sys_regs = ctxt->shadow_sys_regs;
+   } else {
+   flush_special_regs(vcpu);
+   ctxt->hw_sys_regs = ctxt->sys_regs;
+   }
+}
+
+/**
+ * kvm_arm_restore_shadow_state -- write back shadow state from guest
+ * @vcpu: The VCPU pointer
+ */
+void kvm_arm_restore_shadow_state(struct kvm_vcpu *vcpu)
+{
+   if (unlikely(vcpu_mode_el2(vcpu)))
+   sync_shadow_special_regs(vcpu);
+   else
+   sync_special_regs(vcpu);
+}
+
 void kvm_arm_init_cpu_context(kvm_cpu_context_t *cpu_ctxt)
 {
/* This is to set hw_sys_regs of host_cpu_context */
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 13/38] KVM: arm64: Create shadow EL1 registers

2017-07-18 Thread Jintack Lim
From: Christoffer Dall <christoffer.d...@linaro.org>

When entering virtual EL2, we need to reflect virtual EL2 register
states to corresponding shadow EL1 registers. We can simply copy them if
their formats are identical.  Otherwise, we need to convert EL2 register
state to EL1 register state.

When entering EL1/EL0, we need a special care for MPIDR_EL1.  Read of
this register returns the value of VMPIDR_EL2, so when a VM has the
virtual EL2, the value of MPIDR_EL1 should come from the virtual
VMPIDR_EL2.

Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/context.c | 81 
 1 file changed, 81 insertions(+)

diff --git a/arch/arm64/kvm/context.c b/arch/arm64/kvm/context.c
index 2645787..e965049 100644
--- a/arch/arm64/kvm/context.c
+++ b/arch/arm64/kvm/context.c
@@ -17,6 +17,74 @@
 
 #include 
 #include 
+#include 
+
+struct el1_el2_map {
+   enum vcpu_sysregel1;
+   enum vcpu_sysregel2;
+};
+
+/*
+ * List of EL2 registers which can be directly applied to EL1 registers to
+ * emulate running EL2 in EL1.
+ */
+static const struct el1_el2_map el1_el2_map[] = {
+   { AMAIR_EL1, AMAIR_EL2 },
+   { MAIR_EL1, MAIR_EL2 },
+   { TTBR0_EL1, TTBR0_EL2 },
+   { ACTLR_EL1, ACTLR_EL2 },
+   { AFSR0_EL1, AFSR0_EL2 },
+   { AFSR1_EL1, AFSR1_EL2 },
+   { SCTLR_EL1, SCTLR_EL2 },
+   { VBAR_EL1, VBAR_EL2 },
+};
+
+static inline u64 tcr_el2_ips_to_tcr_el1_ps(u64 tcr_el2)
+{
+   return ((tcr_el2 & TCR_EL2_PS_MASK) >> TCR_EL2_PS_SHIFT)
+   << TCR_IPS_SHIFT;
+}
+
+static inline u64 cptr_to_cpacr(u64 cptr_el2)
+{
+   u64 cpacr_el1 = 0;
+
+   if (!(cptr_el2 & CPTR_EL2_TFP))
+   cpacr_el1 |= CPACR_EL1_FPEN;
+   if (cptr_el2 & CPTR_EL2_TTA)
+   cpacr_el1 |= CPACR_EL1_TTA;
+
+   return cpacr_el1;
+}
+
+static void flush_shadow_el1_sysregs(struct kvm_vcpu *vcpu)
+{
+   u64 *s_sys_regs = vcpu->arch.ctxt.shadow_sys_regs;
+   u64 tcr_el2;
+   int i;
+
+   for (i = 0; i < ARRAY_SIZE(el1_el2_map); i++) {
+   const struct el1_el2_map *map = _el2_map[i];
+
+   s_sys_regs[map->el1] = vcpu_sys_reg(vcpu, map->el2);
+   }
+
+   tcr_el2 = vcpu_sys_reg(vcpu, TCR_EL2);
+   s_sys_regs[TCR_EL1] =
+   TCR_EPD1 |  /* disable TTBR1_EL1 */
+   ((tcr_el2 & TCR_EL2_TBI) ? TCR_TBI0 : 0) |
+   tcr_el2_ips_to_tcr_el1_ps(tcr_el2) |
+   (tcr_el2 & TCR_EL2_TG0_MASK) |
+   (tcr_el2 & TCR_EL2_ORGN0_MASK) |
+   (tcr_el2 & TCR_EL2_IRGN0_MASK) |
+   (tcr_el2 & TCR_EL2_T0SZ_MASK);
+
+   /* Rely on separate VMID for VA context, always use ASID 0 */
+   s_sys_regs[TTBR0_EL1] &= ~GENMASK_ULL(63, 48);
+   s_sys_regs[TTBR1_EL1] = 0;
+
+   s_sys_regs[CPACR_EL1] = cptr_to_cpacr(vcpu_sys_reg(vcpu, CPTR_EL2));
+}
 
 static void flush_shadow_special_regs(struct kvm_vcpu *vcpu)
 {
@@ -72,6 +140,17 @@ static void sync_special_regs(struct kvm_vcpu *vcpu)
ctxt->gp_regs.spsr[KVM_SPSR_EL1] = ctxt->hw_spsr_el1;
 }
 
+static void setup_mpidr_el1(struct kvm_vcpu *vcpu)
+{
+   /*
+* A non-secure EL0 or EL1 read of MPIDR_EL1 returns
+* the value of VMPIDR_EL2. For nested virtualization,
+* it comes from the virtual VMPIDR_EL2.
+*/
+   if (nested_virt_in_use(vcpu))
+   vcpu_sys_reg(vcpu, MPIDR_EL1) = vcpu_sys_reg(vcpu, VMPIDR_EL2);
+}
+
 /**
  * kvm_arm_setup_shadow_state -- prepare shadow state based on emulated mode
  * @vcpu: The VCPU pointer
@@ -82,9 +161,11 @@ void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu)
 
if (unlikely(vcpu_mode_el2(vcpu))) {
flush_shadow_special_regs(vcpu);
+   flush_shadow_el1_sysregs(vcpu);
ctxt->hw_sys_regs = ctxt->shadow_sys_regs;
} else {
flush_special_regs(vcpu);
+   setup_mpidr_el1(vcpu);
ctxt->hw_sys_regs = ctxt->sys_regs;
}
 }
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 19/38] KVM: arm64: Trap CPACR_EL1 access in virtual EL2

2017-07-18 Thread Jintack Lim
For the same reason we trap virtual memory register accesses in virtual
EL2, we trap CPACR_EL1 access too; We allow the virtual EL2 mode to
access EL1 system register state instead of the virtual EL2 one.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/hyp/switch.c | 10 +++---
 arch/arm64/kvm/sys_regs.c   | 10 +-
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index ec91cd08..d513da9 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -42,7 +42,8 @@ bool __hyp_text __fpsimd_enabled(void)
return __fpsimd_is_enabled()();
 }
 
-static void __hyp_text __activate_traps_vhe(void)
+static void __hyp_text __activate_traps_vhe(struct kvm_vcpu *vcpu)
+
 {
u64 val;
 
@@ -54,12 +55,15 @@ static void __hyp_text __activate_traps_vhe(void)
write_sysreg(__kvm_hyp_vector, vbar_el1);
 }
 
-static void __hyp_text __activate_traps_nvhe(void)
+static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
+
 {
u64 val;
 
val = CPTR_EL2_DEFAULT;
val |= CPTR_EL2_TTA | CPTR_EL2_TFP;
+   if (vcpu_mode_el2(vcpu))
+   val |= CPTR_EL2_TCPAC;
write_sysreg(val, cptr_el2);
 }
 
@@ -99,7 +103,7 @@ static void __hyp_text __activate_traps(struct kvm_vcpu 
*vcpu)
write_sysreg(0, pmselr_el0);
write_sysreg(ARMV8_PMU_USERENR_MASK, pmuserenr_el0);
write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
-   __activate_traps_arch()();
+   __activate_traps_arch()(vcpu);
 }
 
 static void __hyp_text __deactivate_traps_vhe(void)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index b83fef2..7062645 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -960,6 +960,14 @@ static bool access_vbar(struct kvm_vcpu *vcpu,
return true;
 }
 
+static bool access_cpacr(struct kvm_vcpu *vcpu,
+   struct sys_reg_params *p,
+   const struct sys_reg_desc *r)
+{
+   access_rw(p, _sys_reg(vcpu, r->reg));
+   return true;
+}
+
 /*
  * Architected system registers.
  * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
@@ -1013,7 +1021,7 @@ static bool access_vbar(struct kvm_vcpu *vcpu,
 
{ SYS_DESC(SYS_MPIDR_EL1), NULL, reset_mpidr, MPIDR_EL1 },
{ SYS_DESC(SYS_SCTLR_EL1), access_vm_reg, reset_val, SCTLR_EL1, 
0x00C50078 },
-   { SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 },
+   { SYS_DESC(SYS_CPACR_EL1), access_cpacr, reset_val, CPACR_EL1, 0 },
{ SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 },
{ SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 },
{ SYS_DESC(SYS_TCR_EL1), access_vm_reg, reset_val, TCR_EL1, 0 },
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 15/38] KVM: arm64: Move exception macros and enums to a common file

2017-07-18 Thread Jintack Lim
These macros and enums can be reused to inject exceptions
for nested virtualization.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_emulate.h | 12 
 arch/arm64/kvm/inject_fault.c| 12 
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h 
b/arch/arm64/include/asm/kvm_emulate.h
index 14c4ce9..94f98cc 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -31,6 +31,18 @@
 #include 
 #include 
 
+#define CURRENT_EL_SP_EL0_VECTOR   0x0
+#define CURRENT_EL_SP_ELx_VECTOR   0x200
+#define LOWER_EL_AArch64_VECTOR0x400
+#define LOWER_EL_AArch32_VECTOR0x600
+
+enum exception_type {
+   except_type_sync= 0,
+   except_type_irq = 0x80,
+   except_type_fiq = 0x100,
+   except_type_serror  = 0x180,
+};
+
 unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num);
 unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu);
 
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index da6a8cf..94679fb 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -28,11 +28,6 @@
 #define PSTATE_FAULT_BITS_64   (PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | \
 PSR_I_BIT | PSR_D_BIT)
 
-#define CURRENT_EL_SP_EL0_VECTOR   0x0
-#define CURRENT_EL_SP_ELx_VECTOR   0x200
-#define LOWER_EL_AArch64_VECTOR0x400
-#define LOWER_EL_AArch32_VECTOR0x600
-
 static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
 {
unsigned long cpsr;
@@ -101,13 +96,6 @@ static void inject_abt32(struct kvm_vcpu *vcpu, bool 
is_pabt,
*fsr = 0x14;
 }
 
-enum exception_type {
-   except_type_sync= 0,
-   except_type_irq = 0x80,
-   except_type_fiq = 0x100,
-   except_type_serror  = 0x180,
-};
-
 static u64 get_except_vector(struct kvm_vcpu *vcpu, enum exception_type type)
 {
u64 exc_offset;
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 10/38] KVM: arm/arm64: Add a framework to prepare virtual EL2 execution

2017-07-18 Thread Jintack Lim
From: Christoffer Dall <christoffer.d...@linaro.org>

Add functions setting up and restoring the guest's context on each entry
and exit. These functions will come in handy when we want to use
different context for normal EL0/EL1 and virtual EL2 execution.

No functional change yet.

Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm/include/asm/kvm_emulate.h   |   4 ++
 arch/arm64/include/asm/kvm_emulate.h |   4 ++
 arch/arm64/kvm/Makefile  |   2 +-
 arch/arm64/kvm/context.c |  54 
 arch/arm64/kvm/hyp/sysreg-sr.c   | 117 +++
 virt/kvm/arm/arm.c   |  14 +
 6 files changed, 140 insertions(+), 55 deletions(-)
 create mode 100644 arch/arm64/kvm/context.c

diff --git a/arch/arm/include/asm/kvm_emulate.h 
b/arch/arm/include/asm/kvm_emulate.h
index 399cd75e..0a03b7d 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -47,6 +47,10 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 
reg_num,
 void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
 void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
 
+static inline void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu) { };
+static inline void kvm_arm_restore_shadow_state(struct kvm_vcpu *vcpu) { };
+static inline void kvm_arm_init_cpu_context(kvm_cpu_context_t *cpu_ctxt) { };
+
 static inline bool kvm_condition_valid(const struct kvm_vcpu *vcpu)
 {
return kvm_condition_valid32(vcpu);
diff --git a/arch/arm64/include/asm/kvm_emulate.h 
b/arch/arm64/include/asm/kvm_emulate.h
index 5d6f3d0..14c4ce9 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -42,6 +42,10 @@
 void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
 void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
 
+void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu);
+void kvm_arm_restore_shadow_state(struct kvm_vcpu *vcpu);
+void kvm_arm_init_cpu_context(kvm_cpu_context_t *cpu_ctxt);
+
 static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
 {
vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index f513047..5762337 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -15,7 +15,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/kvm_main.o 
$(KVM)/coalesced_mmio.o $(KVM)/e
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arm.o $(KVM)/arm/mmu.o 
$(KVM)/arm/mmio.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/psci.o $(KVM)/arm/perf.o
 
-kvm-$(CONFIG_KVM_ARM_HOST) += inject_fault.o regmap.o
+kvm-$(CONFIG_KVM_ARM_HOST) += inject_fault.o regmap.o context.o
 kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
 kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o sys_regs.o 
sys_regs_generic_v8.o
 kvm-$(CONFIG_KVM_ARM_HOST) += vgic-sys-reg-v3.o
diff --git a/arch/arm64/kvm/context.c b/arch/arm64/kvm/context.c
new file mode 100644
index 000..bc43e66
--- /dev/null
+++ b/arch/arm64/kvm/context.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 - Linaro Ltd.
+ * Author: Christoffer Dall <christoffer.d...@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include 
+#include 
+
+/**
+ * kvm_arm_setup_shadow_state -- prepare shadow state based on emulated mode
+ * @vcpu: The VCPU pointer
+ */
+void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu)
+{
+   struct kvm_cpu_context *ctxt = >arch.ctxt;
+
+   ctxt->hw_pstate = *vcpu_cpsr(vcpu);
+   ctxt->hw_sys_regs = ctxt->sys_regs;
+   ctxt->hw_sp_el1 = ctxt->gp_regs.sp_el1;
+   ctxt->hw_elr_el1 = ctxt->gp_regs.elr_el1;
+   ctxt->hw_spsr_el1 = ctxt->gp_regs.spsr[KVM_SPSR_EL1];
+}
+
+/**
+ * kvm_arm_restore_shadow_state -- write back shadow state from guest
+ * @vcpu: The VCPU pointer
+ */
+void kvm_arm_restore_shadow_state(struct kvm_vcpu *vcpu)
+{
+   struct kvm_cpu_context *ctxt = >arch.ctxt;
+
+   *vcpu_cpsr(vcpu) = ctxt->hw_pstate;
+   ctxt->gp_regs.sp_el1 = ctxt->hw_sp_el1;
+   ctxt->gp_regs.elr_el1 = ctxt->hw_elr_el1;
+   ctxt->gp_regs.spsr[KVM_SPSR_EL1] = ctxt->hw_spsr_el1;
+}
+
+void kvm_arm_init_cpu_context(kvm_cpu_context_t *cpu_ctxt)
+{
+   /* This is to set hw_sys_regs of host_cpu_context */

[RFC PATCH v2 14/38] KVM: arm64: Synchronize EL1 system registers on virtual EL2 entry and exit

2017-07-18 Thread Jintack Lim
When running in virtual EL2 we use the shadow EL1 systerm register array
for the save/restore process, so that hardware and especially the memory
subsystem behaves as code written for EL2 expects while really running
in EL1.

This works great for EL1 system register accesses that we trap, because
these accesses will be written into the virtual state for the EL1 system
registers used when eventually switching the VCPU mode to EL1.

However, there was a collection of EL1 system registers which we do not
trap, and as a consequence all save/restore operations of these
registers were happening locally in the shadow array, with no benefit to
software actually running in virtual EL1 at all.

To fix this, simply synchronize the shadow and real EL1 state for these
registers on entry/exit to/from virtual EL2 state.

Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/kvm/context.c | 58 ++--
 1 file changed, 56 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/context.c b/arch/arm64/kvm/context.c
index e965049..e1bc753 100644
--- a/arch/arm64/kvm/context.c
+++ b/arch/arm64/kvm/context.c
@@ -86,6 +86,58 @@ static void flush_shadow_el1_sysregs(struct kvm_vcpu *vcpu)
s_sys_regs[CPACR_EL1] = cptr_to_cpacr(vcpu_sys_reg(vcpu, CPTR_EL2));
 }
 
+
+/*
+ * List of EL0 and EL1 registers which we allow the virtual EL2 mode to access
+ * directly without trapping. This is possible because the impact of
+ * accessing those registers are the same regardless of the exception
+ * levels that are allowed.
+ */
+static const int el1_non_trap_regs[] = {
+   CNTKCTL_EL1,
+   CSSELR_EL1,
+   PAR_EL1,
+   TPIDR_EL0,
+   TPIDR_EL1,
+   TPIDRRO_EL0
+};
+
+/**
+ * copy_shadow_non_trap_el1_state
+ * @vcpu:  The VCPU pointer
+ * @setup: True, if on the way to the guest (called from setup)
+ * False, if returning form the guet (calld from restore)
+ *
+ * Some EL1 registers are accessed directly by the virtual EL2 mode because
+ * they in no way affect execution state in virtual EL2.   However, we must
+ * still ensure that virtual EL2 observes the same state of the EL1 registers
+ * as the normal VM's EL1 mode, so copy this state as needed on setup/restore.
+ */
+static void copy_shadow_non_trap_el1_state(struct kvm_vcpu *vcpu, bool setup)
+{
+   u64 *s_sys_regs = vcpu->arch.ctxt.shadow_sys_regs;
+   int i;
+
+   for (i = 0; i < ARRAY_SIZE(el1_non_trap_regs); i++) {
+   const int sr = el1_non_trap_regs[i];
+
+   if (setup)
+   s_sys_regs[sr] = vcpu_sys_reg(vcpu, sr);
+   else
+   vcpu_sys_reg(vcpu, sr) = s_sys_regs[sr];
+   }
+}
+
+static void sync_shadow_non_trap_el1_state(struct kvm_vcpu *vcpu)
+{
+   copy_shadow_non_trap_el1_state(vcpu, false);
+}
+
+static void flush_shadow_non_trap_el1_state(struct kvm_vcpu *vcpu)
+{
+   copy_shadow_non_trap_el1_state(vcpu, true);
+}
+
 static void flush_shadow_special_regs(struct kvm_vcpu *vcpu)
 {
struct kvm_cpu_context *ctxt = >arch.ctxt;
@@ -162,6 +214,7 @@ void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu)
if (unlikely(vcpu_mode_el2(vcpu))) {
flush_shadow_special_regs(vcpu);
flush_shadow_el1_sysregs(vcpu);
+   flush_shadow_non_trap_el1_state(vcpu);
ctxt->hw_sys_regs = ctxt->shadow_sys_regs;
} else {
flush_special_regs(vcpu);
@@ -176,9 +229,10 @@ void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu)
  */
 void kvm_arm_restore_shadow_state(struct kvm_vcpu *vcpu)
 {
-   if (unlikely(vcpu_mode_el2(vcpu)))
+   if (unlikely(vcpu_mode_el2(vcpu))) {
sync_shadow_special_regs(vcpu);
-   else
+   sync_shadow_non_trap_el1_state(vcpu);
+   } else
sync_special_regs(vcpu);
 }
 
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 09/38] KVM: arm64: Add the shadow context for virtual EL2 execution

2017-07-18 Thread Jintack Lim
With the nested virtualization support, a hypervisor running inside a VM
(i.e. a guest hypervisor) is now deprivilaged and runs in EL1 instead of
EL2. So, the host hypervisor manages the shadow context for the virtual
EL2 execution.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_host.h | 13 +
 1 file changed, 13 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_host.h 
b/arch/arm64/include/asm/kvm_host.h
index 57dccde..46880c3 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -229,6 +229,19 @@ struct kvm_cpu_context {
};
 
u64 el2_special_regs[NR_EL2_SPECIAL_REGS];
+
+   u64 shadow_sys_regs[NR_SYS_REGS];  /* only used for virtual EL2 */
+
+   /*
+* hw_* will be written to the hardware when entering to a VM.
+* They have either the virtual EL2 or EL1/EL0 context depending
+* on the vcpu mode.
+*/
+   u64 *hw_sys_regs;
+   u64 hw_sp_el1;
+   u64 hw_pstate;
+   u64 hw_elr_el1;
+   u64 hw_spsr_el1;
 };
 
 typedef struct kvm_cpu_context kvm_cpu_context_t;
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 08/38] KVM: arm64: Add EL2 special registers to vcpu context

2017-07-18 Thread Jintack Lim
To support the virtual EL2 execution, we need to maintain the EL2
special registers such as SPSR_EL2, ELR_EL2 and SP_EL2 in vcpu context.

Note that SP_EL2 is not accessible in EL2, so we don't need a trap
handler for this register.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_host.h | 12 
 arch/arm64/include/asm/sysreg.h   |  4 
 arch/arm64/kvm/sys_regs.c | 38 +-
 arch/arm64/kvm/sys_regs.h |  8 
 4 files changed, 57 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h 
b/arch/arm64/include/asm/kvm_host.h
index 1dc4ed6..57dccde 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -171,6 +171,15 @@ enum vcpu_sysreg {
NR_SYS_REGS /* Nothing after this line! */
 };
 
+enum el2_special_regs {
+   __INVALID_EL2_SPECIAL_REG__,
+   SPSR_EL2,   /* Saved Program Status Register (EL2) */
+   ELR_EL2,/* Exception Link Register (EL2) */
+   SP_EL2, /* Stack Pointer (EL2) */
+
+   NR_EL2_SPECIAL_REGS
+};
+
 /* 32bit mapping */
 #define c0_MPIDR   (MPIDR_EL1 * 2) /* MultiProcessor ID Register */
 #define c0_CSSELR  (CSSELR_EL1 * 2)/* Cache Size Selection Register */
@@ -218,6 +227,8 @@ struct kvm_cpu_context {
u64 sys_regs[NR_SYS_REGS];
u32 copro[NR_COPRO_REGS];
};
+
+   u64 el2_special_regs[NR_EL2_SPECIAL_REGS];
 };
 
 typedef struct kvm_cpu_context kvm_cpu_context_t;
@@ -307,6 +318,7 @@ struct kvm_vcpu_arch {
 
 #define vcpu_gp_regs(v)(&(v)->arch.ctxt.gp_regs)
 #define vcpu_sys_reg(v,r)  ((v)->arch.ctxt.sys_regs[(r)])
+#define vcpu_el2_sreg(v,r) ((v)->arch.ctxt.el2_special_regs[(r)])
 /*
  * CP14 and CP15 live in the same array, as they are backed by the
  * same system registers.
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 9277c4a..98c32ef 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -268,6 +268,8 @@
 
 #define SYS_DACR32_EL2 sys_reg(3, 4, 3, 0, 0)
 
+#define SYS_SPSR_EL2   sys_reg(3, 4, 4, 0, 0)
+#define SYS_ELR_EL2sys_reg(3, 4, 4, 0, 1)
 #define SYS_SP_EL1 sys_reg(3, 4, 4, 1, 0)
 
 #define SYS_IFSR32_EL2 sys_reg(3, 4, 5, 0, 1)
@@ -332,6 +334,8 @@
 #define SYS_CNTVOFF_EL2sys_reg(3, 4, 14, 0, 3)
 #define SYS_CNTHCTL_EL2sys_reg(3, 4, 14, 1, 0)
 
+#define SYS_SP_EL2 sys_reg(3, 6, 4, 1, 0)
+
 /* Common SCTLR_ELx flags. */
 #define SCTLR_ELx_EE(1 << 25)
 #define SCTLR_ELx_I(1 << 12)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 1568f8b..2b3ed70 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -900,15 +900,33 @@ static inline void access_rw(struct sys_reg_params *p, 
u64 *sysreg)
*sysreg = p->regval;
 }
 
+static u64 *get_special_reg(struct kvm_vcpu *vcpu, struct sys_reg_params *p)
+{
+   u64 reg = sys_reg(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2);
+
+   switch (reg) {
+   case SYS_SP_EL1:
+   return >arch.ctxt.gp_regs.sp_el1;
+   case SYS_ELR_EL2:
+   return _el2_sreg(vcpu, ELR_EL2);
+   case SYS_SPSR_EL2:
+   return _el2_sreg(vcpu, SPSR_EL2);
+   default:
+   return NULL;
+   };
+}
+
 static bool trap_el2_regs(struct kvm_vcpu *vcpu,
 struct sys_reg_params *p,
 const struct sys_reg_desc *r)
 {
-   /* SP_EL1 is NOT maintained in sys_regs array */
-   if (sys_reg(p->Op0, p->Op1, p->CRn, p->CRm, p->Op2) == SYS_SP_EL1)
-   access_rw(p, >arch.ctxt.gp_regs.sp_el1);
-   else
-   access_rw(p, _sys_reg(vcpu, r->reg));
+   u64 *sys_reg;
+
+   sys_reg = get_special_reg(vcpu, p);
+   if (!sys_reg)
+   sys_reg = _sys_reg(vcpu, r->reg);
+
+   access_rw(p, sys_reg);
 
return true;
 }
@@ -1116,6 +1134,8 @@ static bool trap_el2_regs(struct kvm_vcpu *vcpu,
 
{ SYS_DESC(SYS_DACR32_EL2), NULL, reset_unknown, DACR32_EL2 },
 
+   { SYS_DESC(SYS_SPSR_EL2), trap_el2_regs, reset_special, SPSR_EL2, 0 },
+   { SYS_DESC(SYS_ELR_EL2), trap_el2_regs, reset_special, ELR_EL2, 0 },
{ SYS_DESC(SYS_SP_EL1), trap_el2_regs },
 
{ SYS_DESC(SYS_IFSR32_EL2), NULL, reset_unknown, IFSR32_EL2 },
@@ -1138,6 +1158,8 @@ static bool trap_el2_regs(struct kvm_vcpu *vcpu,
 
{ SYS_DESC(SYS_CNTVOFF_EL2), trap_el2_regs, reset_val, CNTVOFF_EL2, 0 },
{ SYS_DESC(SYS_CNTHCTL_EL2), trap_el2_regs, reset_val, CNTHCTL_EL2, 0 },
+
+   { SYS_DESC(SYS_SP_EL2), NULL, reset_special, SP_EL2, 0},
 };
 
 static bool trap_dbgidr(struct kvm_vcpu *vcpu,
@@ -2271,6 

[RFC PATCH v2 05/38] KVM: arm64: Allow userspace to set PSR_MODE_EL2x

2017-07-18 Thread Jintack Lim
From: Christoffer Dall 

We were not allowing userspace to set a more privileged mode for the VCPU
than EL1, but now that we support nesting with a virtual EL2 mode, do
allow this!

Signed-off-by: Christoffer Dall 
---
 arch/arm64/kvm/guest.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index 5c7f657..5e673ae 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -117,6 +117,8 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct 
kvm_one_reg *reg)
case PSR_MODE_EL0t:
case PSR_MODE_EL1t:
case PSR_MODE_EL1h:
+   case PSR_MODE_EL2h:
+   case PSR_MODE_EL2t:
break;
default:
err = -EINVAL;
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 07/38] KVM: arm64: Add EL2 system registers to vcpu context

2017-07-18 Thread Jintack Lim
ARM v8.3 introduces a new bit in the HCR_EL2, which is the NV bit. When
this bit is set, accessing EL2 registers in EL1 traps to EL2. In
addition, executing the following instructions in EL1 will trap to EL2:
tlbi, at, eret, and msr/mrs instructions to access SP_EL1. Most of the
instructions that trap to EL2 with the NV bit were undef at EL1 prior to
ARM v8.3. The only instruction that was not undef is eret.

This patch sets up a handler for EL2 registers and SP_EL1 register
accesses at EL1. The host hypervisor keeps those register values in
memory, and will emulate their behavior.

This patch doesn't set the NV bit yet. It will be set in a later patch
once nested virtualization support is completed.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm64/include/asm/kvm_host.h | 30 +++-
 arch/arm64/include/asm/sysreg.h   | 37 +
 arch/arm64/kvm/sys_regs.c | 58 +++
 3 files changed, 124 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_host.h 
b/arch/arm64/include/asm/kvm_host.h
index 86d4b6c..1dc4ed6 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -134,12 +134,40 @@ enum vcpu_sysreg {
PMSWINC_EL0,/* Software Increment Register */
PMUSERENR_EL0,  /* User Enable Register */
 
-   /* 32bit specific registers. Keep them at the end of the range */
+   /* 32bit specific registers. */
DACR32_EL2, /* Domain Access Control Register */
IFSR32_EL2, /* Instruction Fault Status Register */
FPEXC32_EL2,/* Floating-Point Exception Control Register */
DBGVCR32_EL2,   /* Debug Vector Catch Register */
 
+   /* EL2 registers sorted ascending by Op0, Op1, CRn, CRm, Op2 */
+   VPIDR_EL2,  /* Virtualization Processor ID Register */
+   VMPIDR_EL2, /* Virtualization Multiprocessor ID Register */
+   SCTLR_EL2,  /* System Control Register (EL2) */
+   ACTLR_EL2,  /* Auxiliary Control Register (EL2) */
+   HCR_EL2,/* Hypervisor Configuration Register */
+   MDCR_EL2,   /* Monitor Debug Configuration Register (EL2) */
+   CPTR_EL2,   /* Architectural Feature Trap Register (EL2) */
+   HSTR_EL2,   /* Hypervisor System Trap Register */
+   HACR_EL2,   /* Hypervisor Auxiliary Control Register */
+   TTBR0_EL2,  /* Translation Table Base Register 0 (EL2) */
+   TCR_EL2,/* Translation Control Register (EL2) */
+   VTTBR_EL2,  /* Virtualization Translation Table Base Register */
+   VTCR_EL2,   /* Virtualization Translation Control Register */
+   AFSR0_EL2,  /* Auxiliary Fault Status Register 0 (EL2) */
+   AFSR1_EL2,  /* Auxiliary Fault Status Register 1 (EL2) */
+   ESR_EL2,/* Exception Syndrome Register (EL2) */
+   FAR_EL2,/* Hypervisor IPA Fault Address Register */
+   HPFAR_EL2,  /* Hypervisor IPA Fault Address Register */
+   MAIR_EL2,   /* Memory Attribute Indirection Register (EL2) */
+   AMAIR_EL2,  /* Auxiliary Memory Attribute Indirection Register 
(EL2) */
+   VBAR_EL2,   /* Vector Base Address Register (EL2) */
+   RVBAR_EL2,  /* Reset Vector Base Address Register */
+   RMR_EL2,/* Reset Management Register */
+   TPIDR_EL2,  /* EL2 Software Thread ID Register */
+   CNTVOFF_EL2,/* Counter-timer Virtual Offset register */
+   CNTHCTL_EL2,/* Counter-timer Hypervisor Control register */
+
NR_SYS_REGS /* Nothing after this line! */
 };
 
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 737ca30..9277c4a 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -250,10 +250,42 @@
 
 #define SYS_PMCCFILTR_EL0  sys_reg (3, 3, 14, 15, 7)
 
+#define SYS_VPIDR_EL2  sys_reg(3, 4, 0, 0, 0)
+#define SYS_VMPIDR_EL2 sys_reg(3, 4, 0, 0, 5)
+
+#define SYS_SCTLR_EL2  sys_reg(3, 4, 1, 0, 0)
+#define SYS_ACTLR_EL2  sys_reg(3, 4, 1, 0, 1)
+#define SYS_HCR_EL2sys_reg(3, 4, 1, 1, 0)
+#define SYS_MDCR_EL2   sys_reg(3, 4, 1, 1, 1)
+#define SYS_CPTR_EL2   sys_reg(3, 4, 1, 1, 2)
+#define SYS_HSTR_EL2   sys_reg(3, 4, 1, 1, 3)
+#define SYS_HACR_EL2   sys_reg(3, 4, 1, 1, 7)
+
+#define SYS_TTBR0_EL2  sys_reg(3, 4, 2, 0, 0)
+#define SYS_TCR_EL2sys_reg(3, 4, 2, 0, 2)
+#define SYS_VTTBR_EL2  sys_reg(3, 4, 2, 1, 0)
+#define SYS_VTCR_EL2   sys_reg(3, 4, 2, 1, 2)
+
 #define SYS_DACR32_EL2 sys_reg(3, 4, 3, 0, 0)
+
+#define SYS_SP_EL1 sys_reg(3, 4, 4, 1, 0)
+
 #define SYS_IFSR32_EL2 sys_reg(3, 4, 5, 0, 1)
+#define SYS_AFSR0_EL2  sys

[RFC PATCH v2 06/38] KVM: arm64: Add vcpu_mode_el2 primitive to support nesting

2017-07-18 Thread Jintack Lim
From: Christoffer Dall 

When running a nested hypervisor we occasionally have to figure out if
the mode we are switching into is the virtual EL2 mode or a regular
EL0/1 mode.

Signed-off-by: Christoffer Dall 
---
 arch/arm/include/asm/kvm_emulate.h   |  6 ++
 arch/arm64/include/asm/kvm_emulate.h | 12 
 2 files changed, 18 insertions(+)

diff --git a/arch/arm/include/asm/kvm_emulate.h 
b/arch/arm/include/asm/kvm_emulate.h
index 9a8a45a..399cd75e 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -77,6 +77,12 @@ static inline bool vcpu_mode_is_32bit(const struct kvm_vcpu 
*vcpu)
return 1;
 }
 
+/* We don't support nesting on arm */
+static inline bool vcpu_mode_el2(const struct kvm_vcpu *vcpu)
+{
+   return false;
+}
+
 static inline unsigned long *vcpu_pc(struct kvm_vcpu *vcpu)
 {
return >arch.ctxt.gp_regs.usr_regs.ARM_pc;
diff --git a/arch/arm64/include/asm/kvm_emulate.h 
b/arch/arm64/include/asm/kvm_emulate.h
index fe39e68..5d6f3d0 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -143,6 +143,18 @@ static inline bool vcpu_mode_priv(const struct kvm_vcpu 
*vcpu)
return mode != PSR_MODE_EL0t;
 }
 
+static inline bool vcpu_mode_el2(const struct kvm_vcpu *vcpu)
+{
+   u32 mode;
+
+   if (vcpu_mode_is_32bit(vcpu))
+   return false;
+
+   mode = *vcpu_cpsr(vcpu) & PSR_MODE_MASK;
+
+   return mode == PSR_MODE_EL2h || mode == PSR_MODE_EL2t;
+}
+
 static inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu)
 {
return vcpu->arch.fault.esr_el2;
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 03/38] KVM: arm64: Add KVM nesting feature

2017-07-18 Thread Jintack Lim
From: Christoffer Dall <christoffer.d...@linaro.org>

Set the initial exception level of the guest to EL2 if nested
virtualization feature is enabled.

Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>
---
 arch/arm64/include/asm/kvm_host.h | 2 +-
 arch/arm64/include/uapi/asm/kvm.h | 1 +
 arch/arm64/kvm/reset.c| 8 
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_host.h 
b/arch/arm64/include/asm/kvm_host.h
index dcc4df8..6df0c7c 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -39,7 +39,7 @@
 
 #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
 
-#define KVM_VCPU_MAX_FEATURES 4
+#define KVM_VCPU_MAX_FEATURES 5
 
 #define KVM_REQ_SLEEP \
KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
diff --git a/arch/arm64/include/uapi/asm/kvm.h 
b/arch/arm64/include/uapi/asm/kvm.h
index 9f3ca24..4a71a72 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -99,6 +99,7 @@ struct kvm_regs {
 #define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */
 #define KVM_ARM_VCPU_PSCI_0_2  2 /* CPU uses PSCI v0.2 */
 #define KVM_ARM_VCPU_PMU_V33 /* Support guest PMUv3 */
+#define KVM_ARM_VCPU_NESTED_VIRT   4 /* Support nested virtualization */
 
 struct kvm_vcpu_init {
__u32 target;
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 3256b92..1353516 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -41,6 +41,11 @@
PSR_F_BIT | PSR_D_BIT),
 };
 
+static const struct kvm_regs default_regs_reset_el2 = {
+   .regs.pstate = (PSR_MODE_EL2h | PSR_A_BIT | PSR_I_BIT |
+   PSR_F_BIT | PSR_D_BIT),
+};
+
 static const struct kvm_regs default_regs_reset32 = {
.regs.pstate = (COMPAT_PSR_MODE_SVC | COMPAT_PSR_A_BIT |
COMPAT_PSR_I_BIT | COMPAT_PSR_F_BIT),
@@ -106,6 +111,9 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
if (!cpu_has_32bit_el1())
return -EINVAL;
cpu_reset = _regs_reset32;
+   } else if (test_bit(KVM_ARM_VCPU_NESTED_VIRT,
+   vcpu->arch.features)) {
+   cpu_reset = _regs_reset_el2;
} else {
cpu_reset = _regs_reset;
}
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 04/38] KVM: arm/arm64: Check if nested virtualization is in use

2017-07-18 Thread Jintack Lim
Nested virtualizaion is in use only if all three conditions are met:
- The architecture supports nested virtualization.
- The kernel parameter is set.
- The userspace uses nested virtualiztion feature.

Signed-off-by: Jintack Lim <jintack@linaro.org>
---
 arch/arm/include/asm/kvm_host.h   | 11 +++
 arch/arm64/include/asm/kvm_host.h |  2 ++
 arch/arm64/kvm/nested.c   | 17 +
 virt/kvm/arm/arm.c|  4 
 4 files changed, 34 insertions(+)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 00b0f97..7e9e6c8 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -303,4 +303,15 @@ static inline int __init kvmarm_nested_cfg(char *buf)
 {
return 0;
 }
+
+static inline int init_nested_virt(void)
+{
+   return 0;
+}
+
+static inline bool nested_virt_in_use(struct kvm_vcpu *vcpu)
+{
+   return false;
+}
+
 #endif /* __ARM_KVM_HOST_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h 
b/arch/arm64/include/asm/kvm_host.h
index 6df0c7c..86d4b6c 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -387,5 +387,7 @@ static inline void __cpu_init_stage2(void)
 }
 
 int __init kvmarm_nested_cfg(char *buf);
+int init_nested_virt(void);
+bool nested_virt_in_use(struct kvm_vcpu *vcpu);
 
 #endif /* __ARM64_KVM_HOST_H__ */
diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index 79f38da..9a05c76 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -24,3 +24,20 @@ int __init kvmarm_nested_cfg(char *buf)
 {
return strtobool(buf, _param);
 }
+
+int init_nested_virt(void)
+{
+   if (nested_param && cpus_have_const_cap(ARM64_HAS_NESTED_VIRT))
+   kvm_info("Nested virtualization is supported\n");
+
+   return 0;
+}
+
+bool nested_virt_in_use(struct kvm_vcpu *vcpu)
+{
+   if (nested_param && cpus_have_const_cap(ARM64_HAS_NESTED_VIRT)
+   && test_bit(KVM_ARM_VCPU_NESTED_VIRT, vcpu->arch.features))
+   return true;
+
+   return false;
+}
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 1c1c772..36aae3a 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -1478,6 +1478,10 @@ int kvm_arch_init(void *opaque)
if (err)
goto out_err;
 
+   err = init_nested_virt();
+   if (err)
+   return err;
+
err = init_subsystems();
if (err)
goto out_hyp;
-- 
1.9.1

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC PATCH v2 00/38] Nested Virtualization on KVM/ARM

2017-07-18 Thread Jintack Lim
Nested virtualization is the ability to run a virtual machine inside another
virtual machine. In other words, it’s about running a hypervisor (the guest
hypervisor) on top of another hypervisor (the host hypervisor).

Supporting nested virtualization on ARM means that the hypervisor provides not
only EL0/EL1 execution environment to VMs as it usually does but also the
virtualization extensions including EL2 execution environment. Once the host
hypervisor provides those execution environments to the VMs, then the guest
hypervisor can run its own VMs (nested VMs) naturally.

This series supports nested virtualization on arm64. ARM recently announced an
extension (ARMv8.3) which has support for nested virtualization[1]. This patch
set is based on the ARMv8.3 specification and tested on the FastModel with
ARMv8.3 extension.

The whole patch set to support nested virtualization is huge over 70
patches, so I categorized them into four parts: CPU, memory, VGIC, and timer
virtualization. This patch series is the first part.
 
CPU virtualization patch series provides basic nested virtualization framework
and instruction emulations including v8.1 VHE feature and v8.3 nested
virtualization feature for VMs.

This patch series again can be divided into four parts. Patch 1 to 5 introduces
nested virtualization by discovering hardware feature, adding a kernel
parameter and allowing the userspace to set the initial CPU mode to EL2.

Patch 6 to 25 are to support the EL2 execution environment, the virtual EL2, to
a VM on v8.0 architecture. We de-privilege the guest hypervisor and emulate the
virtual EL2 mode in EL1 using the hardware features provided by ARMv8.3; The
host hypervisor manages virtual EL2 register state for the guest hypervisor
and shadow EL1 register state that reflects the virtual EL2 register state to
run the guest hypervisor in EL1. 

Patch 26 to 33 add support for the virtual EL2 with Virtualization Host
Extensions. These patches emulate newly defined registers and bits in v8.1 and
allow the virtual EL2 to access EL2 register states via EL1 register accesses
as in the real EL2.

Patch 34 to 38 are to support for the virtual EL2 with nested virtualization.
These enable recursive nested virtualization.

This patch set is tested on the FastModel with the v8.3 extension for arm64 and
a cubietruck for arm32. On the FastModel, the host and the guest kernels are
compiled with and without VHE, so there are four combinations. I was able to
boot SMP Linux in the nested VM on all four configurations and able to run
hackbench. I also checked that regular VMs could boot when the nested
virtualization kernel parameter was not set. On the cubietruck, I also verified
that regular VMs could boot as well.

I'll share my experiment setup shortly.

Even though this work has some limitations and TODOs, I'd appreciate early
feedback on this RFC. Specifically, I'm interested in:

- Overall design to manage vcpu context for the virtual EL2
- Verifying correct EL2 register configurations such as HCR_EL2, CPTR_EL2
  (Patch 30 and 32)
- Patch organization and coding style

This patch series is based on kvm/next d38338e.
The whole patch series including memory, VGIC, and timer patches is available
here:

g...@github.com:columbia/nesting-pub.git rfc-v2

Limitations:
- There are some cases that the target exception level of a VM is ambiguous when
  emulating eret instruction. I'm discussing this issue with Christoffer and
  Marc. Meanwhile, I added a temporary patch (not included in this
  series. f1beaba in the repo) and used 4.10.0 kernel when testing the guest
  hypervisor with VHE.
- Recursive nested virtualization is not tested yet.
- Other hypervisors (such as Xen) on KVM are not tested.

TODO:
- Submit memory, VGIC, and timer patches
- Evaluate regular VM performance to see if there's a negative impact.
- Test other hypervisors such as Xen on KVM
- Test recursive nested virtualization

v1-->v2:
- Added support for the virtual EL2 with VHE
- Rewrote commit messages and comments from the perspective of supporting
  execution environments to VMs, rather than from the perspective of the guest
  hypervisor running in them.
- Fixed a few bugs to make it run on the FastModel.
- Tested on ARMv8.3 with four configurations. (host/guest. with/without VHE.)
- Rebased to kvm/next

[1] 
https://www.community.arm.com/processors/b/blog/posts/armv8-a-architecture-2016-additions

Christoffer Dall (7):
  KVM: arm64: Add KVM nesting feature
  KVM: arm64: Allow userspace to set PSR_MODE_EL2x
  KVM: arm64: Add vcpu_mode_el2 primitive to support nesting
  KVM: arm/arm64: Add a framework to prepare virtual EL2 execution
  arm64: Add missing TCR hw defines
  KVM: arm64: Create shadow EL1 registers
  KVM: arm64: Trap EL1 VM register accesses in virtual EL2

Jintack Lim (31):
  arm64: Add ARM64_HAS_NESTED_VIRT feature
  KVM: arm/arm64: Enable nested virtualization via command-line
  KVM: arm/arm64: Check if nested virtualization is in use
  KVM: ar

Re: [RFC 06/55] KVM: arm64: Add EL2 execution context for nesting

2017-07-03 Thread Jintack Lim
Thanks Christoffer and Marc,

On Mon, Jul 3, 2017 at 5:54 AM, Christoffer Dall <cd...@linaro.org> wrote:
> On Mon, Jul 03, 2017 at 10:32:45AM +0100, Marc Zyngier wrote:
>> On 03/07/17 10:03, Christoffer Dall wrote:
>> > On Mon, Jun 26, 2017 at 10:33:23AM -0400, Jintack Lim wrote:
>> >> Hi Christoffer,
>> >>
>> >> On Wed, Feb 22, 2017 at 6:10 AM, Christoffer Dall <cd...@linaro.org> 
>> >> wrote:
>> >>> On Mon, Jan 09, 2017 at 01:24:02AM -0500, Jintack Lim wrote:
>> >>>> With the nested virtualization support, the context of the guest
>> >>>> includes EL2 register states. The host manages a set of virtual EL2
>> >>>> registers.  In addition to that, the guest hypervisor supposed to run in
>> >>>> EL2 is now deprivilaged and runs in EL1. So, the host also manages a set
>> >>>> of shadow system registers to be able to run the guest hypervisor in
>> >>>> EL1.
>> >>>>
>> >>>> Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>
>> >>>> Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
>> >>>> ---
>> >>>>  arch/arm64/include/asm/kvm_host.h | 54 
>> >>>> +++
>> >>>>  1 file changed, 54 insertions(+)
>> >>>>
>> >>>> diff --git a/arch/arm64/include/asm/kvm_host.h 
>> >>>> b/arch/arm64/include/asm/kvm_host.h
>> >>>> index c0c8b02..ed78d73 100644
>> >>>> --- a/arch/arm64/include/asm/kvm_host.h
>> >>>> +++ b/arch/arm64/include/asm/kvm_host.h
>> >>>> @@ -146,6 +146,42 @@ enum vcpu_sysreg {
>> >>>>   NR_SYS_REGS /* Nothing after this line! */
>> >>>>  };
>> >>>>
>> >>>> +enum el2_regs {
>> >>>> + ELR_EL2,
>> >>>> + SPSR_EL2,
>> >>>> + SP_EL2,
>> >>>> + AMAIR_EL2,
>> >>>> + MAIR_EL2,
>> >>>> + TCR_EL2,
>> >>>> + TTBR0_EL2,
>> >>>> + VTCR_EL2,
>> >>>> + VTTBR_EL2,
>> >>>> + VMPIDR_EL2,
>> >>>> + VPIDR_EL2,  /* 10 */
>> >>>> + MDCR_EL2,
>> >>>> + CNTHCTL_EL2,
>> >>>> + CNTHP_CTL_EL2,
>> >>>> + CNTHP_CVAL_EL2,
>> >>>> + CNTHP_TVAL_EL2,
>> >>>> + CNTVOFF_EL2,
>> >>>> + ACTLR_EL2,
>> >>>> + AFSR0_EL2,
>> >>>> + AFSR1_EL2,
>> >>>> + CPTR_EL2,   /* 20 */
>> >>>> + ESR_EL2,
>> >>>> + FAR_EL2,
>> >>>> + HACR_EL2,
>> >>>> + HCR_EL2,
>> >>>> + HPFAR_EL2,
>> >>>> + HSTR_EL2,
>> >>>> + RMR_EL2,
>> >>>> + RVBAR_EL2,
>> >>>> + SCTLR_EL2,
>> >>>> + TPIDR_EL2,  /* 30 */
>> >>>> + VBAR_EL2,
>> >>>> + NR_EL2_REGS /* Nothing after this line! */
>> >>>> +};
>> >>>
>> >>> Why do we have a separate enum and array for the EL2 regs and not simply
>> >>> expand vcpu_sysreg ?
>> >>
>> >> We can expand vcpu_sysreg for the EL2 system registers. For SP_EL2,
>> >> SPSR_EL2, and ELR_EL2, where is the good place to locate them?.
>> >> SP_EL1, SPSR_EL1, and ELR_EL1 registers are saved in the kvm_regs
>> >> structure instead of sysregs[], so I wonder it's better to put them in
>> >> kvm_regs, too.
>> >>
>> >> BTW, what's the reason that those EL1 registers are in kvm_regs
>> >> instead of sysregs[] in the first place?
>> >>
>> >
>> > This has mostly to do with the way we export things to userspace, and
>> > for historical reasons.
>> >
>> > So we should either expand kvm_regs with the non-sysregs EL2 registers
>> > and expand sys_regs with the EL2 sysregs, or we should put everything
>> > EL2 into an EL2 array.  I feel like the first solution will fit more
>> > nicely into the current design, but I don't have a very strong
>> > preference.
>> >
>> > You should look at the KVM_{GET,SET}_ONE_REG API definition and think
>> > about how your choice will f

Re: [RFC 21/55] KVM: arm64: Forward HVC instruction to the guest hypervisor

2017-06-26 Thread Jintack Lim
On Wed, Feb 22, 2017 at 6:47 AM, Christoffer Dall <cd...@linaro.org> wrote:
> On Mon, Jan 09, 2017 at 01:24:17AM -0500, Jintack Lim wrote:
>> Forward exceptions due to hvc instruction to the guest hypervisor.
>>
>> Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>
>> ---
>>  arch/arm64/include/asm/kvm_nested.h |  5 +
>>  arch/arm64/kvm/Makefile |  1 +
>>  arch/arm64/kvm/handle_exit.c| 11 +++
>>  arch/arm64/kvm/handle_exit_nested.c | 27 +++
>>  4 files changed, 44 insertions(+)
>>  create mode 100644 arch/arm64/include/asm/kvm_nested.h
>>  create mode 100644 arch/arm64/kvm/handle_exit_nested.c
>>
>> diff --git a/arch/arm64/include/asm/kvm_nested.h 
>> b/arch/arm64/include/asm/kvm_nested.h
>> new file mode 100644
>> index 000..620b4d3
>> --- /dev/null
>> +++ b/arch/arm64/include/asm/kvm_nested.h
>> @@ -0,0 +1,5 @@
>> +#ifndef __ARM64_KVM_NESTED_H__
>> +#define __ARM64_KVM_NESTED_H__
>> +
>> +int handle_hvc_nested(struct kvm_vcpu *vcpu);
>> +#endif
>> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
>> index b342bdd..9c35e9a 100644
>> --- a/arch/arm64/kvm/Makefile
>> +++ b/arch/arm64/kvm/Makefile
>> @@ -35,4 +35,5 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/irqchip.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
>>  kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
>>
>> +kvm-$(CONFIG_KVM_ARM_NESTED_HYP) += handle_exit_nested.o
>>  kvm-$(CONFIG_KVM_ARM_NESTED_HYP) += emulate-nested.o
>> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
>> index a891684..208be16 100644
>> --- a/arch/arm64/kvm/handle_exit.c
>> +++ b/arch/arm64/kvm/handle_exit.c
>> @@ -29,6 +29,10 @@
>>  #include 
>>  #include 
>>
>> +#ifdef CONFIG_KVM_ARM_NESTED_HYP
>> +#include 
>> +#endif
>> +
>>  #define CREATE_TRACE_POINTS
>>  #include "trace.h"
>>
>> @@ -42,6 +46,13 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct 
>> kvm_run *run)
>>   kvm_vcpu_hvc_get_imm(vcpu));
>>   vcpu->stat.hvc_exit_stat++;
>>
>> +#ifdef CONFIG_KVM_ARM_NESTED_HYP
>> + ret = handle_hvc_nested(vcpu);
>> + if (ret < 0 && ret != -EINVAL)
>> + return ret;
>> + else if (ret >= 0)
>> + return ret;
>> +#endif
>>   ret = kvm_psci_call(vcpu);
>>   if (ret < 0) {
>>   kvm_inject_undefined(vcpu);
>> diff --git a/arch/arm64/kvm/handle_exit_nested.c 
>> b/arch/arm64/kvm/handle_exit_nested.c
>> new file mode 100644
>> index 000..a6ce23b
>> --- /dev/null
>> +++ b/arch/arm64/kvm/handle_exit_nested.c
>> @@ -0,0 +1,27 @@
>> +/*
>> + * Copyright (C) 2016 - Columbia University
>> + * Author: Jintack Lim <jint...@cs.columbia.edu>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include 
>> +#include 
>> +
>> +#include 
>> +
>> +/* We forward all hvc instruction to the guest hypervisor. */
>> +int handle_hvc_nested(struct kvm_vcpu *vcpu)
>> +{
>> + return kvm_inject_nested_sync(vcpu, kvm_vcpu_get_hsr(vcpu));
>> +}
>
> I don't understand the logic here or in the caller above.  Do we really
> forward *all" hvc calls to the guest hypervisor now, so that we no
> longer support any hypercalls from the VM?  That seems a little rough
> and probably requires some more discussions.

So I think if we run a VM with the EL2 support, then all hvc calls
from the VM should be forwarded to the virtual EL2.

I may miss something obvious, so can you (or anyone) come up with some
cases that the host hypervisor needs to directly handle hvc from the
VM with the EL2 support?

Thanks,
Jintack

>
> Thanks,
> -Christoffer
>
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [RFC 06/55] KVM: arm64: Add EL2 execution context for nesting

2017-06-26 Thread Jintack Lim
Hi Christoffer,

On Wed, Feb 22, 2017 at 6:10 AM, Christoffer Dall <cd...@linaro.org> wrote:
> On Mon, Jan 09, 2017 at 01:24:02AM -0500, Jintack Lim wrote:
>> With the nested virtualization support, the context of the guest
>> includes EL2 register states. The host manages a set of virtual EL2
>> registers.  In addition to that, the guest hypervisor supposed to run in
>> EL2 is now deprivilaged and runs in EL1. So, the host also manages a set
>> of shadow system registers to be able to run the guest hypervisor in
>> EL1.
>>
>> Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>
>> Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
>> ---
>>  arch/arm64/include/asm/kvm_host.h | 54 
>> +++
>>  1 file changed, 54 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/kvm_host.h 
>> b/arch/arm64/include/asm/kvm_host.h
>> index c0c8b02..ed78d73 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -146,6 +146,42 @@ enum vcpu_sysreg {
>>   NR_SYS_REGS /* Nothing after this line! */
>>  };
>>
>> +enum el2_regs {
>> + ELR_EL2,
>> + SPSR_EL2,
>> + SP_EL2,
>> + AMAIR_EL2,
>> + MAIR_EL2,
>> + TCR_EL2,
>> + TTBR0_EL2,
>> + VTCR_EL2,
>> + VTTBR_EL2,
>> + VMPIDR_EL2,
>> + VPIDR_EL2,  /* 10 */
>> + MDCR_EL2,
>> + CNTHCTL_EL2,
>> + CNTHP_CTL_EL2,
>> + CNTHP_CVAL_EL2,
>> + CNTHP_TVAL_EL2,
>> + CNTVOFF_EL2,
>> + ACTLR_EL2,
>> + AFSR0_EL2,
>> + AFSR1_EL2,
>> + CPTR_EL2,   /* 20 */
>> + ESR_EL2,
>> + FAR_EL2,
>> + HACR_EL2,
>> + HCR_EL2,
>> + HPFAR_EL2,
>> + HSTR_EL2,
>> + RMR_EL2,
>> + RVBAR_EL2,
>> + SCTLR_EL2,
>> + TPIDR_EL2,  /* 30 */
>> + VBAR_EL2,
>> + NR_EL2_REGS /* Nothing after this line! */
>> +};
>
> Why do we have a separate enum and array for the EL2 regs and not simply
> expand vcpu_sysreg ?

We can expand vcpu_sysreg for the EL2 system registers. For SP_EL2,
SPSR_EL2, and ELR_EL2, where is the good place to locate them?.
SP_EL1, SPSR_EL1, and ELR_EL1 registers are saved in the kvm_regs
structure instead of sysregs[], so I wonder it's better to put them in
kvm_regs, too.

BTW, what's the reason that those EL1 registers are in kvm_regs
instead of sysregs[] in the first place?

>
>> +
>>  /* 32bit mapping */
>>  #define c0_MPIDR (MPIDR_EL1 * 2) /* MultiProcessor ID Register */
>>  #define c0_CSSELR(CSSELR_EL1 * 2)/* Cache Size Selection Register */
>> @@ -193,6 +229,23 @@ struct kvm_cpu_context {
>>   u64 sys_regs[NR_SYS_REGS];
>>   u32 copro[NR_COPRO_REGS];
>>   };
>> +
>> + u64 el2_regs[NR_EL2_REGS]; /* only used for nesting */
>> + u64 shadow_sys_regs[NR_SYS_REGS];  /* only used for virtual EL2 */
>> +
>> + /*
>> +  * hw_* will be used when switching to a VM. They point to either
>> +  * the virtual EL2 or EL1/EL0 context depending on vcpu mode.
>
> don't they either point to the shadow sys regs or the the normal EL1
> sysregs?

Ah, this is a general comment for all three members below.

>
>> +  */
>> +
>> + /* pointing shadow_sys_regs or sys_regs */
>
> that's what this comment seems to indicate, so there's some duplicity
> here.

And this comment is for hw_sys_regs specifically.

>
>> + u64 *hw_sys_regs;
>> +
>> + /* copy of either gp_regs.sp_el1 or el2_regs[SP_EL2] */
>> + u64 hw_sp_el1;
>> +
>> + /* pstate written to SPSR_EL2 */
>> + u64 hw_pstate;
>>  };
>>
>>  typedef struct kvm_cpu_context kvm_cpu_context_t;
>> @@ -277,6 +330,7 @@ struct kvm_vcpu_arch {
>>
>>  #define vcpu_gp_regs(v)  (&(v)->arch.ctxt.gp_regs)
>>  #define vcpu_sys_reg(v,r)((v)->arch.ctxt.sys_regs[(r)])
>> +#define vcpu_el2_reg(v, r)   ((v)->arch.ctxt.el2_regs[(r)])
>>  /*
>>   * CP14 and CP15 live in the same array, as they are backed by the
>>   * same system registers.
>> --
>> 1.9.1
>>
>>
>
___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [RFC 10/55] KVM: arm64: Synchronize EL1 system registers on virtual EL2 entry and exit

2017-06-06 Thread Jintack Lim
Hi Bandan,

On Tue, Jun 6, 2017 at 4:16 PM, Bandan Das <b...@redhat.com> wrote:
> Jintack Lim <jint...@cs.columbia.edu> writes:
>
>> From: Christoffer Dall <christoffer.d...@linaro.org>
>>
>> When running in virtual EL2 we use the shadow EL1 systerm register array
>> for the save/restore process, so that hardware and especially the memory
>> subsystem behaves as code written for EL2 expects while really running
>> in EL1.
>>
>> This works great for EL1 system register accesses that we trap, because
>> these accesses will be written into the virtual state for the EL1 system
>> registers used when eventually switching the VCPU mode to EL1.
>>
>> However, there was a collection of EL1 system registers which we do not
>> trap, and as a consequence all save/restore operations of these
>> registers were happening locally in the shadow array, with no benefit to
>> software actually running in virtual EL1 at all.
>>
>> To fix this, simply synchronize the shadow and real EL1 state for these
>> registers on entry/exit to/from virtual EL2 state.
>>
>> Signed-off-by: Christoffer Dall <christoffer.d...@linaro.org>
>> Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>
>> ---
>>  arch/arm64/kvm/context.c | 47 
>> +++
>>  1 file changed, 47 insertions(+)
>>
>> diff --git a/arch/arm64/kvm/context.c b/arch/arm64/kvm/context.c
>> index 2e9e386..0025dd9 100644
>> --- a/arch/arm64/kvm/context.c
>> +++ b/arch/arm64/kvm/context.c
>> @@ -88,6 +88,51 @@ static void create_shadow_el1_sysregs(struct kvm_vcpu 
>> *vcpu)
>>   s_sys_regs[CPACR_EL1] = cptr_el2_to_cpacr_el1(el2_regs[CPTR_EL2]);
>>  }
>>
>> +/*
>> + * List of EL1 registers which we allow the virtual EL2 mode to access
>> + * directly without trapping and which haven't been paravirtualized.
>> + *
>> + * Probably CNTKCTL_EL1 should not be copied but be accessed via trap. 
>> Because,
>> + * the guest hypervisor running in EL1 can be affected by event streams
>> + * configured via CNTKCTL_EL1, which it does not expect. We don't have a
>> + * mechanism to trap on CNTKCTL_EL1 as of now (v8.3), keep it in here 
>> instead.
>> + */
>> +static const int el1_non_trap_regs[] = {
>> + CNTKCTL_EL1,
>> + CSSELR_EL1,
>> + PAR_EL1,
>> + TPIDR_EL0,
>> + TPIDR_EL1,
>> + TPIDRRO_EL0
>> +};
>> +
>
> Do we trap on all register accesses in the non-nested case +
> all accesses to the memory access registers ? I am trying to
> understand how we decide what registers to trap on. For example,
> shouldn't accesses to CSSELR_EL1, the cache size selection register
> be trapped ?

So, the principle is that we trap on EL1 register accesses from the
virtual EL2 if those EL1 register accesses without trap make the guest
hypervisor's execution different from what it should be if it really
runs in EL2. (e.g. A write operation to TTBR0_EL1 from the guest
hypervisor without trap will change the guest hypervisor's page table
base. However, if a hypervisor runs in EL2, this operation only
affects the software running in EL1, not itself.)

For non-nested case, this patch does not introduce any additional
traps since there's no virtual EL2 state.

For CSSELR_EL1 case, this register can be used at any exception level
other than EL0 and its behavior is the same whether it is executed in
EL1 or EL2. In other words, the guest hypervisor can interact with
this register in EL1 just the way a non-nesting hypervisor would do in
EL2.

Thanks,
Jintack

>
> Bandan
>
>
>> +/**
>> + * sync_shadow_el1_state - Going to/from the virtual EL2 state, sync state
>> + * @vcpu:The VCPU pointer
>> + * @setup:   True, if on the way to the guest (called from setup)
>> + *   False, if returning form the guet (calld from restore)
>> + *
>> + * Some EL1 registers are accessed directly by the virtual EL2 mode because
>> + * they in no way affect execution state in virtual EL2.   However, we must
>> + * still ensure that virtual EL2 observes the same state of the EL1 
>> registers
>> + * as the normal VM's EL1 mode, so copy this state as needed on 
>> setup/restore.
>> + */
>> +static void sync_shadow_el1_state(struct kvm_vcpu *vcpu, bool setup)
>> +{
>> + u64 *sys_regs = vcpu->arch.ctxt.sys_regs;
>> + u64 *s_sys_regs = vcpu->arch.ctxt.shadow_sys_regs;
>> + int i;
>> +
>> + for (i = 0; i < ARRAY_SIZE(el1_non_trap_regs); i++) {
>> + const int sr = el1_non_trap_regs[i];
>> +
>> + 

Re: [RFC 11/55] KVM: arm64: Emulate taking an exception to the guest hypervisor

2017-06-06 Thread Jintack Lim
On Tue, Jun 6, 2017 at 6:07 PM, Bandan Das <b...@redhat.com> wrote:
> Hi Jintack,
>
> Jintack Lim <jintack@linaro.org> writes:
>
>> Hi Bandan,
>>
>> On Tue, Jun 6, 2017 at 4:21 PM, Bandan Das <b...@redhat.com> wrote:
>>> Jintack Lim <jint...@cs.columbia.edu> writes:
>>>
>>>> Emulate taking an exception to the guest hypervisor running in the
>>>> virtual EL2 as described in ARM ARM AArch64.TakeException().
>>>
>>> ARM newbie here, I keep thinking of ARM ARM as a typo ;)
>>
>> ARM ARM means ARM Architecture Reference Manual :)
>>
>>> ...
>>>> +static inline int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 
>>>> esr_el2)
>>>> +{
>>>> + kvm_err("Unexpected call to %s for the non-nesting configuration\n",
>>>> +  __func__);
>>>> + return -EINVAL;
>>>> +}
>>>> +
>>>> +static inline int kvm_inject_nested_irq(struct kvm_vcpu *vcpu)
>>>> +{
>>>> + kvm_err("Unexpected call to %s for the non-nesting configuration\n",
>>>> +  __func__);
>>>> + return -EINVAL;
>>>> +}
>>>> +
>>>
>>> I see these function stubs for aarch32 in the patches. I don't see how they
>>> can actually be called though. Is this because eventually, there will be
>>> a virtual el2 mode for aarch32 ?
>>
>> Current RFC doesn't support nested virtualization on 32bit arm
>> architecture and those functions will be never called. Those functions
>> are there for the compilation.
>
> Do you mean that compilation will fail ?

Compilation on 32bit arm architecture will fail without them.

> It seems these functions are
> defined separately in 32/64 bit specific header files. Or is it that
> 64 bit compilation also depends on the 32 bit header file ?

It's only for 32bit architecture. For example, kvm_inject_nested_irq()
is called in virt/kvm/arm/vgic/vgic.c which is shared between 32 and
64 bit.

>
> Bandan
>
>> Thanks,
>> Jintack
>>
>>>
>>> Bandan
>>>
>>>>  static inline void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu) { };
>>>>  static inline void kvm_arm_restore_shadow_state(struct kvm_vcpu *vcpu) { 
>>>> };
>>>>  static inline void kvm_arm_init_cpu_context(kvm_cpu_context_t *cpu_ctxt) 
>>>> { };
>>>> diff --git a/arch/arm64/include/asm/kvm_emulate.h 
>>>> b/arch/arm64/include/asm/kvm_emulate.h
>>>> index 8892c82..0987ee4 100644
>>>> --- a/arch/arm64/include/asm/kvm_emulate.h
>>>> +++ b/arch/arm64/include/asm/kvm_emulate.h
>>>> @@ -42,6 +42,25 @@
>>>>  void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
>>>>  void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
>>>>
>>>> +#ifdef CONFIG_KVM_ARM_NESTED_HYP
>>>> +int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2);
>>>> +int kvm_inject_nested_irq(struct kvm_vcpu *vcpu);
>>>> +#else
>>>> +static inline int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 
>>>> esr_el2)
>>>> +{
>>>> + kvm_err("Unexpected call to %s for the non-nesting configuration\n",
>>>> +  __func__);
>>>> + return -EINVAL;
>>>> +}
>>>> +
>>>> +static inline int kvm_inject_nested_irq(struct kvm_vcpu *vcpu)
>>>> +{
>>>> + kvm_err("Unexpected call to %s for the non-nesting configuration\n",
>>>> +  __func__);
>>>> + return -EINVAL;
>>>> +}
>>>> +#endif
>>>> +
>>>>  void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu);
>>>>  void kvm_arm_restore_shadow_state(struct kvm_vcpu *vcpu);
>>>>  void kvm_arm_init_cpu_context(kvm_cpu_context_t *cpu_ctxt);
>>>> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
>>>> index 7811d27..b342bdd 100644
>>>> --- a/arch/arm64/kvm/Makefile
>>>> +++ b/arch/arm64/kvm/Makefile
>>>> @@ -34,3 +34,5 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-its.o
>>>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/irqchip.o
>>>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
>>>>  kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
>>>> +
>>>> +kvm-$(CONFIG_KVM_ARM_NESTED_HYP) += emulate-nested.o
>>>> diff --git a/arch/arm64/kvm/e

Re: [RFC 11/55] KVM: arm64: Emulate taking an exception to the guest hypervisor

2017-06-06 Thread Jintack Lim
Hi Bandan,

On Tue, Jun 6, 2017 at 4:21 PM, Bandan Das <b...@redhat.com> wrote:
> Jintack Lim <jint...@cs.columbia.edu> writes:
>
>> Emulate taking an exception to the guest hypervisor running in the
>> virtual EL2 as described in ARM ARM AArch64.TakeException().
>
> ARM newbie here, I keep thinking of ARM ARM as a typo ;)

ARM ARM means ARM Architecture Reference Manual :)

> ...
>> +static inline int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2)
>> +{
>> + kvm_err("Unexpected call to %s for the non-nesting configuration\n",
>> +  __func__);
>> + return -EINVAL;
>> +}
>> +
>> +static inline int kvm_inject_nested_irq(struct kvm_vcpu *vcpu)
>> +{
>> + kvm_err("Unexpected call to %s for the non-nesting configuration\n",
>> +  __func__);
>> + return -EINVAL;
>> +}
>> +
>
> I see these function stubs for aarch32 in the patches. I don't see how they
> can actually be called though. Is this because eventually, there will be
> a virtual el2 mode for aarch32 ?

Current RFC doesn't support nested virtualization on 32bit arm
architecture and those functions will be never called. Those functions
are there for the compilation.

Thanks,
Jintack

>
> Bandan
>
>>  static inline void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu) { };
>>  static inline void kvm_arm_restore_shadow_state(struct kvm_vcpu *vcpu) { };
>>  static inline void kvm_arm_init_cpu_context(kvm_cpu_context_t *cpu_ctxt) { 
>> };
>> diff --git a/arch/arm64/include/asm/kvm_emulate.h 
>> b/arch/arm64/include/asm/kvm_emulate.h
>> index 8892c82..0987ee4 100644
>> --- a/arch/arm64/include/asm/kvm_emulate.h
>> +++ b/arch/arm64/include/asm/kvm_emulate.h
>> @@ -42,6 +42,25 @@
>>  void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
>>  void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
>>
>> +#ifdef CONFIG_KVM_ARM_NESTED_HYP
>> +int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2);
>> +int kvm_inject_nested_irq(struct kvm_vcpu *vcpu);
>> +#else
>> +static inline int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2)
>> +{
>> + kvm_err("Unexpected call to %s for the non-nesting configuration\n",
>> +  __func__);
>> + return -EINVAL;
>> +}
>> +
>> +static inline int kvm_inject_nested_irq(struct kvm_vcpu *vcpu)
>> +{
>> + kvm_err("Unexpected call to %s for the non-nesting configuration\n",
>> +  __func__);
>> + return -EINVAL;
>> +}
>> +#endif
>> +
>>  void kvm_arm_setup_shadow_state(struct kvm_vcpu *vcpu);
>>  void kvm_arm_restore_shadow_state(struct kvm_vcpu *vcpu);
>>  void kvm_arm_init_cpu_context(kvm_cpu_context_t *cpu_ctxt);
>> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
>> index 7811d27..b342bdd 100644
>> --- a/arch/arm64/kvm/Makefile
>> +++ b/arch/arm64/kvm/Makefile
>> @@ -34,3 +34,5 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-its.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/irqchip.o
>>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
>>  kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
>> +
>> +kvm-$(CONFIG_KVM_ARM_NESTED_HYP) += emulate-nested.o
>> diff --git a/arch/arm64/kvm/emulate-nested.c 
>> b/arch/arm64/kvm/emulate-nested.c
>> new file mode 100644
>> index 000..59d147f
>> --- /dev/null
>> +++ b/arch/arm64/kvm/emulate-nested.c
>> @@ -0,0 +1,66 @@
>> +/*
>> + * Copyright (C) 2016 - Columbia University
>> + * Author: Jintack Lim <jint...@cs.columbia.edu>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include 
>> +#include 
>> +
>> +#include 
>> +
>> +#include "trace.h"
>> +
>> +#define  EL2_EXCEPT_SYNC_OFFSET  0x400
>> +#define  EL2_EXCEPT_ASYNC_OFFSET 0x480
>> +
>> +
>> +/*
>> + *  Emulate taki

Re: [PATCH v2] KVM: arm/arm64: Let vcpu thread modify its own active state

2017-03-06 Thread Jintack Lim
Hi Christoffer,

thanks for submitting this patch.

On Mon, Mar 6, 2017 at 8:42 AM, Christoffer Dall
<christoffer.d...@linaro.org> wrote:
> From: Jintack Lim <jint...@cs.columbia.edu>
>
> Currently, if a vcpu thread tries to change the active state of an
> interrupt which is already on the same vcpu's AP list,

"it'll loop forever" is remove accidentally in the commit message in v2?

> Since the VGIC
> mmio handler is called after a vcpu has already synced back the LR state
> to the struct vgic_irq, we can just let it proceed safely.
>
> Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>
> ---
> Changes since v1:
>  - Reworked comment
>  - Consider userspace accesses
>  - Get the right requester VCPU for GICv3 private IRQ accesses
>  - Tested using kvm-unit-tests and verified that it deadlocked without
>this patch and passed the test with this patch :)

nice!

>
>  virt/kvm/arm/vgic/vgic-mmio.c | 32 
>  1 file changed, 24 insertions(+), 8 deletions(-)
>
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index 3654b4c..2a5db13 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -180,21 +180,37 @@ unsigned long vgic_mmio_read_active(struct kvm_vcpu 
> *vcpu,
>  static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq 
> *irq,
> bool new_active_state)
>  {
> +   struct kvm_vcpu *requester_vcpu;
> spin_lock(>irq_lock);
> +
> +   /*
> +* The vcpu parameter here can mean multiple things depending on how
> +* this function is called; when handling a trap from the kernel it
> +* depends on the GIC version, and these functions are also called as
> +* part of save/restore from userspace.
> +*
> +* Therefore, we have to figure out the requester in a reliable way.
> +*
> +* When accessing VGIC state from user space, the requester_vcpu is
> +* NULL, which is fine, because we guarantee that no VCPUs are running
> +* when accessing VGIC state from user space so irq->vcpu->cpu is
> +* always -1.
> +*/
> +   requester_vcpu = kvm_arm_get_running_vcpu();
> +
> /*
>  * If this virtual IRQ was written into a list register, we
>  * have to make sure the CPU that runs the VCPU thread has
> -* synced back LR state to the struct vgic_irq.  We can only
> -* know this for sure, when either this irq is not assigned to
> -* anyone's AP list anymore, or the VCPU thread is not
> -* running on any CPUs.
> +* synced back the LR state to the struct vgic_irq.
>  *
> -* In the opposite case, we know the VCPU thread may be on its
> -* way back from the guest and still has to sync back this
> -* IRQ, so we release and re-acquire the spin_lock to let the
> -* other thread sync back the IRQ.
> +* As long as the conditions below are true, we know the VCPU thread
> +* may be on its way back from the guest (we kicked the VCPU thread in
> +* vgic_change_active_prepare)  and still has to sync back this IRQ,
> +* so we release and re-acquire the spin_lock to let the other thread
> +* sync back the IRQ.
>  */
> while (irq->vcpu && /* IRQ may have state in an LR somewhere */
> +  irq->vcpu != requester_vcpu && /* Current thread is not the 
> VCPU thread */
>irq->vcpu->cpu != -1) /* VCPU thread is running */
> cond_resched_lock(>irq_lock);
>
> --
> 2.5.0
>
>

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [RFC 00/55] Nested Virtualization on KVM/ARM

2017-02-24 Thread Jintack Lim
[My previous reply had HTML subpart, which made the e-mail look
terrible and being rejected from mailing lists. So, I'm sending it
again. Sorry for the inconvenience]

Hi Christoffer,

On Wed, Feb 22, 2017 at 1:23 PM, Christoffer Dall <cd...@linaro.org> wrote:
> Hi Jintack,
>
>
> On Mon, Jan 09, 2017 at 01:23:56AM -0500, Jintack Lim wrote:
>> Nested virtualization is the ability to run a virtual machine inside another
>> virtual machine. In other words, it’s about running a hypervisor (the guest
>> hypervisor) on top of another hypervisor (the host hypervisor).
>>
>> This series supports nested virtualization on arm64. ARM recently announced 
>> an
>> extension (ARMv8.3) which has support for nested virtualization[1]. This 
>> series
>> is based on the ARMv8.3 specification.
>>
>> Supporting nested virtualization means that the hypervisor provides not only
>> EL0/EL1 execution environment with VMs as it usually does, but also the
>> virtualization extensions including EL2 execution environment with the VMs.
>> Once the host hypervisor provides those execution environment with the VMs,
>> then the guest hypervisor can run its own VMs (nested VMs) naturally.
>>
>> To support nested virtualization on ARM the hypervisor must emulate a virtual
>> execution environment consisting of EL2, EL1, and EL0, as the guest 
>> hypervisor
>> will run in a virtual EL2 mode.  Normally KVM/ARM only emulated a VM 
>> supporting
>> EL1/0 running in their respective native CPU modes, but with nested
>> virtualization we deprivilege the guest hypervisor and emulate a virtual EL2
>> execution mode in EL1 using the hardware features provided by ARMv8.3 to trap
>> EL2 operations to EL1. To do that the host hypervisor needs to manage EL2
>> register state for the guest hypervisor, and shadow EL1 register state that
>> reflects the EL2 register state to run the guest hypervisor in EL1. See 
>> patch 6
>> through 10 for this.
>>
>> For memory virtualization, the biggest issue is that we now have more than 
>> two
>> stages of translation when running nested VMs. We choose to merge two stage-2
>> page tables (one from the guest hypervisor and the other from the host
>> hypervisor) and create shadow stage-2 page tables, which have mappings from 
>> the
>> nested VM’s physical addresses to the machine physical addresses. Stage-1
>> translation is done by the hardware as is done for the normal VMs.
>>
>> To provide VGIC support to the guest hypervisor, we emulate the GIC
>> virtualization extensions using trap-and-emulate to a virtual GIC Hypervisor
>> Control Interface.  Furthermore, we can still use the GIC VE hardware 
>> features
>> to deliver virtual interrupts to the nested VM, by directly mapping the GIC
>> VCPU interface to the nested VM and switching the content of the GIC 
>> Hypervisor
>> Control interface when alternating between a nested VM and a normal VM.  See
>> patches 25 through 32, and 50 through 52 for more information.
>>
>> For timer virtualization, the guest hypervisor expects to have access to the
>> EL2 physical timer, the EL1 physical timer and the virtual timer. So, the 
>> host
>> hypervisor needs to provide all of them. The virtual timer is always 
>> available
>> to VMs. The physical timer is available to VMs via my previous patch 
>> series[3].
>> The EL2 physical timer is not supported yet in this RFC. We plan to support
>> this as it is required to run other guest hypervisors such as Xen.
>>
>> Even though this work is not complete (see limitations below), I'd appreciate
>> early feedback on this RFC. Specifically, I'm interested in:
>> - Is it better to have a kernel config or to make it configurable at runtime?
>> - I wonder if the data structure for memory management makes sense.
>> - What architecture version do we support for the guest hypervisor, and how?
>>   For example, do we always support all architecture versions or the same
>>   architecture as the underlying hardware platform? Or is it better
>>   to make it configurable from the userspace?
>> - Initial comments on the overall design?
>>
>> This patch series is based on kvm-arm-for-4.9-rc7 with the patch series to 
>> provide
>> VMs with the EL1 physical timer[2].
>>
>> Git: https://github.com/columbia/nesting-pub/tree/rfc-v1
>>
>> Testing:
>> We have tested this on ARMv8.0 (Applied Micro X-Gene)[3] since ARMv8.3 
>> hardware
>> is not available yet. We have paravirtualized the guest hypervisor to trap to
>> EL2 as specified in ARMv8.3 specific

Re: [RFC 00/55] Nested Virtualization on KVM/ARM

2017-02-24 Thread Jintack Lim
Hi Christoffer,

On Wed, Feb 22, 2017 at 1:23 PM, Christoffer Dall <cd...@linaro.org> wrote:

> Hi Jintack,
>
>
> On Mon, Jan 09, 2017 at 01:23:56AM -0500, Jintack Lim wrote:
> > Nested virtualization is the ability to run a virtual machine inside
> another
> > virtual machine. In other words, it’s about running a hypervisor (the
> guest
> > hypervisor) on top of another hypervisor (the host hypervisor).
> >
> > This series supports nested virtualization on arm64. ARM recently
> announced an
> > extension (ARMv8.3) which has support for nested virtualization[1]. This
> series
> > is based on the ARMv8.3 specification.
> >
> > Supporting nested virtualization means that the hypervisor provides not
> only
> > EL0/EL1 execution environment with VMs as it usually does, but also the
> > virtualization extensions including EL2 execution environment with the
> VMs.
> > Once the host hypervisor provides those execution environment with the
> VMs,
> > then the guest hypervisor can run its own VMs (nested VMs) naturally.
> >
> > To support nested virtualization on ARM the hypervisor must emulate a
> virtual
> > execution environment consisting of EL2, EL1, and EL0, as the guest
> hypervisor
> > will run in a virtual EL2 mode.  Normally KVM/ARM only emulated a VM
> supporting
> > EL1/0 running in their respective native CPU modes, but with nested
> > virtualization we deprivilege the guest hypervisor and emulate a virtual
> EL2
> > execution mode in EL1 using the hardware features provided by ARMv8.3 to
> trap
> > EL2 operations to EL1. To do that the host hypervisor needs to manage EL2
> > register state for the guest hypervisor, and shadow EL1 register state
> that
> > reflects the EL2 register state to run the guest hypervisor in EL1. See
> patch 6
> > through 10 for this.
> >
> > For memory virtualization, the biggest issue is that we now have more
> than two
> > stages of translation when running nested VMs. We choose to merge two
> stage-2
> > page tables (one from the guest hypervisor and the other from the host
> > hypervisor) and create shadow stage-2 page tables, which have mappings
> from the
> > nested VM’s physical addresses to the machine physical addresses. Stage-1
> > translation is done by the hardware as is done for the normal VMs.
> >
> > To provide VGIC support to the guest hypervisor, we emulate the GIC
> > virtualization extensions using trap-and-emulate to a virtual GIC
> Hypervisor
> > Control Interface.  Furthermore, we can still use the GIC VE hardware
> features
> > to deliver virtual interrupts to the nested VM, by directly mapping the
> GIC
> > VCPU interface to the nested VM and switching the content of the GIC
> Hypervisor
> > Control interface when alternating between a nested VM and a normal VM.
> See
> > patches 25 through 32, and 50 through 52 for more information.
> >
> > For timer virtualization, the guest hypervisor expects to have access to
> the
> > EL2 physical timer, the EL1 physical timer and the virtual timer. So,
> the host
> > hypervisor needs to provide all of them. The virtual timer is always
> available
> > to VMs. The physical timer is available to VMs via my previous patch
> series[3].
> > The EL2 physical timer is not supported yet in this RFC. We plan to
> support
> > this as it is required to run other guest hypervisors such as Xen.
> >
> > Even though this work is not complete (see limitations below), I'd
> appreciate
> > early feedback on this RFC. Specifically, I'm interested in:
> > - Is it better to have a kernel config or to make it configurable at
> runtime?
> > - I wonder if the data structure for memory management makes sense.
> > - What architecture version do we support for the guest hypervisor, and
> how?
> >   For example, do we always support all architecture versions or the same
> >   architecture as the underlying hardware platform? Or is it better
> >   to make it configurable from the userspace?
> > - Initial comments on the overall design?
> >
> > This patch series is based on kvm-arm-for-4.9-rc7 with the patch series
> to provide
> > VMs with the EL1 physical timer[2].
> >
> > Git: https://github.com/columbia/nesting-pub/tree/rfc-v1
> >
> > Testing:
> > We have tested this on ARMv8.0 (Applied Micro X-Gene)[3] since ARMv8.3
> hardware
> > is not available yet. We have paravirtualized the guest hypervisor to
> trap to
> > EL2 as specified in ARMv8.3 specification using hvc instruction. We plan
> to
> > test this on ARMv8.3 model, an

Re: [RFC v4 00/10] Provide the EL1 physical timer to the VM

2017-02-03 Thread Jintack Lim
On Fri, Feb 3, 2017 at 11:14 AM, Marc Zyngier <marc.zyng...@arm.com> wrote:
> On 03/02/17 15:19, Jintack Lim wrote:
>> The ARM architecture defines the EL1 physical timer and the virtual timer,
>> and it is reasonable for an OS to expect to be able to access both.
>> However, the current KVM implementation does not provide the EL1 physical
>> timer to VMs but terminates VMs on access to the timer.
>>
>> This patch series enables VMs to use the EL1 physical timer through
>> trap-and-emulate only on arm64. The KVM host emulates each EL1 physical
>> timer register access and sets up the background timer accordingly.  When
>> the background timer expires, the KVM host injects EL1 physical timer
>> interrupts to the VM.  Alternatively, it's also possible to allow VMs to
>> access the EL1 physical timer without trapping.  However, this requires
>> somehow using the EL2 physical timer for the Linux host while running the
>> VM instead of the EL1 physical timer.  Right now I just implemented
>> trap-and-emulate because this was straightforward to do, and I leave it to
>> future work to determine if transferring the EL1 physical timer state to
>> the EL2 timer provides any performance benefit.
>>
>> This feature will be useful for any OS that wishes to access the EL1
>> physical timer. Nested virtualization is one of those use cases. A nested
>> hypervisor running inside a VM would think it has full access to the
>> hardware and naturally tries to use the EL1 physical timer as Linux would
>> do. Other nested hypervisors may try to use the EL2 physical timer as Xen
>> would do, but supporting the EL2 physical timer to the VM is out of scope
>> of this patch series. This patch series will make it easy to add the EL2
>> timer support in the future, though.
>>
>> Note that Linux VMs booting in EL1 will be unaffected by this patch series
>> and will continue to use only the virtual timer and this patch series will
>> therefore not introduce any performance degredation as a result of
>> trap-and-emulate.
>>
>> v3 => v4:
>>  - Fix a bug that prevents a VM from booting on 32-bit architecture
>>  - Clarify that the emulated physical timer is only supported on arm64
>>in the cover letter
>
> Hi Jintack,
>
> I've now applied this to queue, and will push it out later today.

Thanks, Marc.

>
> Out of curiosity, is there any reason why this is arm64 only?

It was simply because I didn't have a convenient 32bit architecture
develop environment at hand and didn't spend time to set it up myself
:(
(As specified in the nesting RFC patch series cover letter, the
nesting patches are compiled, but not tested on 32-bit architecture
yet.)
I guess it's time to set it up.

> As far as
> I can tell, we're only missing the cp15 handling (both for arm and in
> the 32bit handling in arm64).

I think so, too. I can't promise when, but I'll try to add those once
I set the develop environment.

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

___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC v4 09/10] KVM: arm64: Add the EL1 physical timer access handler

2017-02-03 Thread Jintack Lim
KVM traps on the EL1 phys timer accesses from VMs, but it doesn't handle
those traps. This results in terminating VMs. Instead, set a handler for
the EL1 phys timer access, and inject an undefined exception as an
intermediate step.

Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>
Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 34 ++
 1 file changed, 34 insertions(+)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index caa47ce..1cd3464 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -820,6 +820,30 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
  CRm((0b1100 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)), \
  access_pmu_evtyper, reset_unknown, (PMEVTYPER0_EL0 + n), }
 
+static bool access_cntp_tval(struct kvm_vcpu *vcpu,
+   struct sys_reg_params *p,
+   const struct sys_reg_desc *r)
+{
+   kvm_inject_undefined(vcpu);
+   return true;
+}
+
+static bool access_cntp_ctl(struct kvm_vcpu *vcpu,
+   struct sys_reg_params *p,
+   const struct sys_reg_desc *r)
+{
+   kvm_inject_undefined(vcpu);
+   return true;
+}
+
+static bool access_cntp_cval(struct kvm_vcpu *vcpu,
+   struct sys_reg_params *p,
+   const struct sys_reg_desc *r)
+{
+   kvm_inject_undefined(vcpu);
+   return true;
+}
+
 /*
  * Architected system registers.
  * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
@@ -1029,6 +1053,16 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, 
struct sys_reg_params *p,
{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b), Op2(0b011),
  NULL, reset_unknown, TPIDRRO_EL0 },
 
+   /* CNTP_TVAL_EL0 */
+   { Op0(0b11), Op1(0b011), CRn(0b1110), CRm(0b0010), Op2(0b000),
+ access_cntp_tval },
+   /* CNTP_CTL_EL0 */
+   { Op0(0b11), Op1(0b011), CRn(0b1110), CRm(0b0010), Op2(0b001),
+ access_cntp_ctl },
+   /* CNTP_CVAL_EL0 */
+   { Op0(0b11), Op1(0b011), CRn(0b1110), CRm(0b0010), Op2(0b010),
+ access_cntp_cval },
+
/* PMEVCNTRn_EL0 */
PMU_PMEVCNTR_EL0(0),
PMU_PMEVCNTR_EL0(1),
-- 
1.9.1


___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC v4 06/10] KVM: arm/arm64: Update the physical timer interrupt level

2017-02-03 Thread Jintack Lim
Now that we maintain the EL1 physical timer register states of VMs,
update the physical timer interrupt level along with the virtual one.

Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>
Acked-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 virt/kvm/arm/arch_timer.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index dbd0af1..7f9a664 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -186,6 +186,7 @@ static int kvm_timer_update_state(struct kvm_vcpu *vcpu)
 {
struct arch_timer_cpu *timer = >arch.timer_cpu;
struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
+   struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
 
/*
 * If userspace modified the timer registers via SET_ONE_REG before
@@ -199,6 +200,9 @@ static int kvm_timer_update_state(struct kvm_vcpu *vcpu)
if (kvm_timer_should_fire(vtimer) != vtimer->irq.level)
kvm_timer_update_irq(vcpu, !vtimer->irq.level, vtimer);
 
+   if (kvm_timer_should_fire(ptimer) != ptimer->irq.level)
+   kvm_timer_update_irq(vcpu, !ptimer->irq.level, ptimer);
+
return 0;
 }
 
-- 
1.9.1


___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC v4 03/10] KVM: arm/arm64: Decouple kvm timer functions from virtual timer

2017-02-03 Thread Jintack Lim
Now that we have a separate structure for timer context, make functions
generic so that they can work with any timer context, not just the
virtual timer context.  This does not change the virtual timer
functionality.

Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>
Acked-by: Marc Zyngier <marc.zyng...@arm.com>
Acked-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm/kvm/arm.c   |  2 +-
 include/kvm/arm_arch_timer.h |  2 +-
 virt/kvm/arm/arch_timer.c| 54 
 3 files changed, 27 insertions(+), 31 deletions(-)

diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index f93f2171..0ecd6cf 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -300,7 +300,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 
 int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
 {
-   return kvm_timer_should_fire(vcpu);
+   return kvm_timer_should_fire(vcpu_vtimer(vcpu));
 }
 
 void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index 2c8560b..f46fa3b 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -66,7 +66,7 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid);
 int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value);
 
-bool kvm_timer_should_fire(struct kvm_vcpu *vcpu);
+bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx);
 void kvm_timer_schedule(struct kvm_vcpu *vcpu);
 void kvm_timer_unschedule(struct kvm_vcpu *vcpu);
 
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 5004a67..5261f98 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -98,13 +98,12 @@ static void kvm_timer_inject_irq_work(struct work_struct 
*work)
kvm_vcpu_kick(vcpu);
 }
 
-static u64 kvm_timer_compute_delta(struct kvm_vcpu *vcpu)
+static u64 kvm_timer_compute_delta(struct arch_timer_context *timer_ctx)
 {
u64 cval, now;
-   struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 
-   cval = vtimer->cnt_cval;
-   now = kvm_phys_timer_read() - vtimer->cntvoff;
+   cval = timer_ctx->cnt_cval;
+   now = kvm_phys_timer_read() - timer_ctx->cntvoff;
 
if (now < cval) {
u64 ns;
@@ -133,7 +132,7 @@ static enum hrtimer_restart kvm_timer_expire(struct hrtimer 
*hrt)
 * PoV (NTP on the host may have forced it to expire
 * early). If we should have slept longer, restart it.
 */
-   ns = kvm_timer_compute_delta(vcpu);
+   ns = kvm_timer_compute_delta(vcpu_vtimer(vcpu));
if (unlikely(ns)) {
hrtimer_forward_now(hrt, ns_to_ktime(ns));
return HRTIMER_RESTART;
@@ -143,43 +142,39 @@ static enum hrtimer_restart kvm_timer_expire(struct 
hrtimer *hrt)
return HRTIMER_NORESTART;
 }
 
-static bool kvm_timer_irq_can_fire(struct kvm_vcpu *vcpu)
+static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx)
 {
-   struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
-
-   return !(vtimer->cnt_ctl & ARCH_TIMER_CTRL_IT_MASK) &&
-   (vtimer->cnt_ctl & ARCH_TIMER_CTRL_ENABLE);
+   return !(timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_IT_MASK) &&
+   (timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_ENABLE);
 }
 
-bool kvm_timer_should_fire(struct kvm_vcpu *vcpu)
+bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
 {
-   struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
u64 cval, now;
 
-   if (!kvm_timer_irq_can_fire(vcpu))
+   if (!kvm_timer_irq_can_fire(timer_ctx))
return false;
 
-   cval = vtimer->cnt_cval;
-   now = kvm_phys_timer_read() - vtimer->cntvoff;
+   cval = timer_ctx->cnt_cval;
+   now = kvm_phys_timer_read() - timer_ctx->cntvoff;
 
return cval <= now;
 }
 
-static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
+static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
+struct arch_timer_context *timer_ctx)
 {
int ret;
-   struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 
BUG_ON(!vgic_initialized(vcpu->kvm));
 
-   vtimer->active_cleared_last = false;
-   vtimer->irq.level = new_level;
-   trace_kvm_timer_update_irq(vcpu->vcpu_id, vtimer->irq.irq,
-  vtimer->irq.level);
+   timer_ctx->active_cleared_last = false;
+   timer_ctx->irq.level = new_level;
+   trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_ctx->irq.irq,
+  timer_ctx->irq.level);
 
-   ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
-vtimer->irq.irq,
-vtimer-&g

[RFC v4 08/10] KVM: arm/arm64: Set up a background timer for the physical timer emulation

2017-02-03 Thread Jintack Lim
Set a background timer for the EL1 physical timer emulation while VMs
are running, so that VMs get the physical timer interrupts in a timely
manner.

Schedule the background timer on entry to the VM and cancel it on exit.
This would not have any performance impact to the guest OSes that
currently use the virtual timer since the physical timer is always not
enabled.

Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>
Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 virt/kvm/arm/arch_timer.c | 25 -
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 0ea7452..33257b5 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -229,6 +229,22 @@ static int kvm_timer_update_state(struct kvm_vcpu *vcpu)
return 0;
 }
 
+/* Schedule the background timer for the emulated timer. */
+static void kvm_timer_emulate(struct kvm_vcpu *vcpu,
+ struct arch_timer_context *timer_ctx)
+{
+   struct arch_timer_cpu *timer = >arch.timer_cpu;
+
+   if (kvm_timer_should_fire(timer_ctx))
+   return;
+
+   if (!kvm_timer_irq_can_fire(timer_ctx))
+   return;
+
+   /*  The timer has not yet expired, schedule a background timer */
+   timer_arm(timer, kvm_timer_compute_delta(timer_ctx));
+}
+
 /*
  * Schedule the background timer before calling kvm_vcpu_block, so that this
  * thread is removed from its waitqueue and made runnable when there's a timer
@@ -286,6 +302,9 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
if (kvm_timer_update_state(vcpu))
return;
 
+   /* Set the background timer for the physical timer emulation. */
+   kvm_timer_emulate(vcpu, vcpu_ptimer(vcpu));
+
/*
* If we enter the guest with the virtual input level to the VGIC
* asserted, then we have already told the VGIC what we need to, and
@@ -348,7 +367,11 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
 {
struct arch_timer_cpu *timer = >arch.timer_cpu;
 
-   BUG_ON(timer_is_armed(timer));
+   /*
+* This is to cancel the background timer for the physical timer
+* emulation if it is set.
+*/
+   timer_disarm(timer);
 
/*
 * The guest could have modified the timer registers or the timer
-- 
1.9.1


___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC v4 05/10] KVM: arm/arm64: Initialize the emulated EL1 physical timer

2017-02-03 Thread Jintack Lim
Initialize the emulated EL1 physical timer with the default irq number.

Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>
Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm/kvm/reset.c | 9 -
 arch/arm64/kvm/reset.c   | 9 -
 include/kvm/arm_arch_timer.h | 3 ++-
 virt/kvm/arm/arch_timer.c| 9 +++--
 4 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/arch/arm/kvm/reset.c b/arch/arm/kvm/reset.c
index 4b5e802..1da8b2d 100644
--- a/arch/arm/kvm/reset.c
+++ b/arch/arm/kvm/reset.c
@@ -37,6 +37,11 @@
.usr_regs.ARM_cpsr = SVC_MODE | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT,
 };
 
+static const struct kvm_irq_level cortexa_ptimer_irq = {
+   { .irq = 30 },
+   .level = 1,
+};
+
 static const struct kvm_irq_level cortexa_vtimer_irq = {
{ .irq = 27 },
.level = 1,
@@ -58,6 +63,7 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
 {
struct kvm_regs *reset_regs;
const struct kvm_irq_level *cpu_vtimer_irq;
+   const struct kvm_irq_level *cpu_ptimer_irq;
 
switch (vcpu->arch.target) {
case KVM_ARM_TARGET_CORTEX_A7:
@@ -65,6 +71,7 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
reset_regs = _regs_reset;
vcpu->arch.midr = read_cpuid_id();
cpu_vtimer_irq = _vtimer_irq;
+   cpu_ptimer_irq = _ptimer_irq;
break;
default:
return -ENODEV;
@@ -77,5 +84,5 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
kvm_reset_coprocs(vcpu);
 
/* Reset arch_timer context */
-   return kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq);
+   return kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq, cpu_ptimer_irq);
 }
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index e95d4f6..d9e9697 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -46,6 +46,11 @@
COMPAT_PSR_I_BIT | COMPAT_PSR_F_BIT),
 };
 
+static const struct kvm_irq_level default_ptimer_irq = {
+   .irq= 30,
+   .level  = 1,
+};
+
 static const struct kvm_irq_level default_vtimer_irq = {
.irq= 27,
.level  = 1,
@@ -104,6 +109,7 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, 
long ext)
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
 {
const struct kvm_irq_level *cpu_vtimer_irq;
+   const struct kvm_irq_level *cpu_ptimer_irq;
const struct kvm_regs *cpu_reset;
 
switch (vcpu->arch.target) {
@@ -117,6 +123,7 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
}
 
cpu_vtimer_irq = _vtimer_irq;
+   cpu_ptimer_irq = _ptimer_irq;
break;
}
 
@@ -130,5 +137,5 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
kvm_pmu_vcpu_reset(vcpu);
 
/* Reset timer */
-   return kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq);
+   return kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq, cpu_ptimer_irq);
 }
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index 6445a3d..f1d2fba0 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -58,7 +58,8 @@ struct arch_timer_cpu {
 int kvm_timer_hyp_init(void);
 int kvm_timer_enable(struct kvm_vcpu *vcpu);
 int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
-const struct kvm_irq_level *irq);
+const struct kvm_irq_level *virt_irq,
+const struct kvm_irq_level *phys_irq);
 void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu);
 void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu);
 void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu);
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 5261f98..dbd0af1 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -327,9 +327,11 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
 }
 
 int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
-const struct kvm_irq_level *irq)
+const struct kvm_irq_level *virt_irq,
+const struct kvm_irq_level *phys_irq)
 {
struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
+   struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
 
/*
 * The vcpu timer irq number cannot be determined in
@@ -337,7 +339,8 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 * kvm_vcpu_set_target(). To handle this, we determine
 * vcpu timer irq number when the vcpu is reset.
 */
-   vtimer->irq.irq = irq->irq;
+   vtimer->irq.irq = virt_irq->irq;
+   ptimer->irq.irq = phys_irq->irq;
 
/*
 * The bits in CNTV_CTL are architecturally reset to UNKNOWN for ARMv8
@@ -346,6 +349,7 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 * the ARMv7 architecture.
 */
vtimer->cnt_ctl = 0;
+   ptimer->cnt_ctl = 0;
kvm_timer_update_state(vcpu);

[RFC v4 07/10] KVM: arm/arm64: Set a background timer to the earliest timer expiration

2017-02-03 Thread Jintack Lim
When scheduling a background timer, consider both of the virtual and
physical timer and pick the earliest expiration time.

Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>
Reviewed-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 arch/arm/kvm/arm.c|  3 ++-
 virt/kvm/arm/arch_timer.c | 53 +++
 2 files changed, 42 insertions(+), 14 deletions(-)

diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 0ecd6cf..21c493a 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -300,7 +300,8 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 
 int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
 {
-   return kvm_timer_should_fire(vcpu_vtimer(vcpu));
+   return kvm_timer_should_fire(vcpu_vtimer(vcpu)) ||
+  kvm_timer_should_fire(vcpu_ptimer(vcpu));
 }
 
 void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 7f9a664..0ea7452 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -118,6 +118,35 @@ static u64 kvm_timer_compute_delta(struct 
arch_timer_context *timer_ctx)
return 0;
 }
 
+static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx)
+{
+   return !(timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_IT_MASK) &&
+   (timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_ENABLE);
+}
+
+/*
+ * Returns the earliest expiration time in ns among guest timers.
+ * Note that it will return 0 if none of timers can fire.
+ */
+static u64 kvm_timer_earliest_exp(struct kvm_vcpu *vcpu)
+{
+   u64 min_virt = ULLONG_MAX, min_phys = ULLONG_MAX;
+   struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
+   struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
+
+   if (kvm_timer_irq_can_fire(vtimer))
+   min_virt = kvm_timer_compute_delta(vtimer);
+
+   if (kvm_timer_irq_can_fire(ptimer))
+   min_phys = kvm_timer_compute_delta(ptimer);
+
+   /* If none of timers can fire, then return 0 */
+   if ((min_virt == ULLONG_MAX) && (min_phys == ULLONG_MAX))
+   return 0;
+
+   return min(min_virt, min_phys);
+}
+
 static enum hrtimer_restart kvm_timer_expire(struct hrtimer *hrt)
 {
struct arch_timer_cpu *timer;
@@ -132,7 +161,7 @@ static enum hrtimer_restart kvm_timer_expire(struct hrtimer 
*hrt)
 * PoV (NTP on the host may have forced it to expire
 * early). If we should have slept longer, restart it.
 */
-   ns = kvm_timer_compute_delta(vcpu_vtimer(vcpu));
+   ns = kvm_timer_earliest_exp(vcpu);
if (unlikely(ns)) {
hrtimer_forward_now(hrt, ns_to_ktime(ns));
return HRTIMER_RESTART;
@@ -142,12 +171,6 @@ static enum hrtimer_restart kvm_timer_expire(struct 
hrtimer *hrt)
return HRTIMER_NORESTART;
 }
 
-static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx)
-{
-   return !(timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_IT_MASK) &&
-   (timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_ENABLE);
-}
-
 bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
 {
u64 cval, now;
@@ -215,26 +238,30 @@ void kvm_timer_schedule(struct kvm_vcpu *vcpu)
 {
struct arch_timer_cpu *timer = >arch.timer_cpu;
struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
+   struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
 
BUG_ON(timer_is_armed(timer));
 
/*
-* No need to schedule a background timer if the guest timer has
+* No need to schedule a background timer if any guest timer has
 * already expired, because kvm_vcpu_block will return before putting
 * the thread to sleep.
 */
-   if (kvm_timer_should_fire(vtimer))
+   if (kvm_timer_should_fire(vtimer) || kvm_timer_should_fire(ptimer))
return;
 
/*
-* If the timer is not capable of raising interrupts (disabled or
+* If both timers are not capable of raising interrupts (disabled or
 * masked), then there's no more work for us to do.
 */
-   if (!kvm_timer_irq_can_fire(vtimer))
+   if (!kvm_timer_irq_can_fire(vtimer) && !kvm_timer_irq_can_fire(ptimer))
return;
 
-   /*  The timer has not yet expired, schedule a background timer */
-   timer_arm(timer, kvm_timer_compute_delta(vtimer));
+   /*
+* The guest timers have not yet expired, schedule a background timer.
+* Set the earliest expiration time among the guest timers.
+*/
+   timer_arm(timer, kvm_timer_earliest_exp(vcpu));
 }
 
 void kvm_timer_unschedule(struct kvm_vcpu *vcpu)
-- 
1.9.1


___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC v4 01/10] KVM: arm/arm64: Abstract virtual timer context into separate structure

2017-02-03 Thread Jintack Lim
Abstract virtual timer context into a separate structure and change all
callers referring to timer registers, irq state and so on. No change in
functionality.

This is about to become very handy when adding the EL1 physical timer.

Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>
Acked-by: Christoffer Dall <christoffer.d...@linaro.org>
Acked-by: Marc Zyngier <marc.zyng...@arm.com>
---
 include/kvm/arm_arch_timer.h | 27 -
 virt/kvm/arm/arch_timer.c| 69 +++-
 virt/kvm/arm/hyp/timer-sr.c  | 10 ---
 3 files changed, 56 insertions(+), 50 deletions(-)

diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index 5c970ce..daad3c1 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -28,15 +28,20 @@ struct arch_timer_kvm {
u64 cntvoff;
 };
 
-struct arch_timer_cpu {
+struct arch_timer_context {
/* Registers: control register, timer value */
-   u32 cntv_ctl;   /* Saved/restored */
-   u64 cntv_cval;  /* Saved/restored */
+   u32 cnt_ctl;
+   u64 cnt_cval;
+
+   /* Timer IRQ */
+   struct kvm_irq_levelirq;
+
+   /* Active IRQ state caching */
+   boolactive_cleared_last;
+};
 
-   /*
-* Anything that is not used directly from assembly code goes
-* here.
-*/
+struct arch_timer_cpu {
+   struct arch_timer_context   vtimer;
 
/* Background timer used when the guest is not running */
struct hrtimer  timer;
@@ -47,12 +52,6 @@ struct arch_timer_cpu {
/* Background timer active */
boolarmed;
 
-   /* Timer IRQ */
-   struct kvm_irq_levelirq;
-
-   /* Active IRQ state caching */
-   boolactive_cleared_last;
-
/* Is the timer enabled */
boolenabled;
 };
@@ -77,4 +76,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
 
 void kvm_timer_init_vhe(void);
+
+#define vcpu_vtimer(v) (&(v)->arch.timer_cpu.vtimer)
 #endif
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 91ecf48..d3556b3 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -37,7 +37,7 @@
 
 void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 {
-   vcpu->arch.timer_cpu.active_cleared_last = false;
+   vcpu_vtimer(vcpu)->active_cleared_last = false;
 }
 
 static u64 kvm_phys_timer_read(void)
@@ -102,7 +102,7 @@ static u64 kvm_timer_compute_delta(struct kvm_vcpu *vcpu)
 {
u64 cval, now;
 
-   cval = vcpu->arch.timer_cpu.cntv_cval;
+   cval = vcpu_vtimer(vcpu)->cnt_cval;
now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff;
 
if (now < cval) {
@@ -144,21 +144,21 @@ static enum hrtimer_restart kvm_timer_expire(struct 
hrtimer *hrt)
 
 static bool kvm_timer_irq_can_fire(struct kvm_vcpu *vcpu)
 {
-   struct arch_timer_cpu *timer = >arch.timer_cpu;
+   struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 
-   return !(timer->cntv_ctl & ARCH_TIMER_CTRL_IT_MASK) &&
-   (timer->cntv_ctl & ARCH_TIMER_CTRL_ENABLE);
+   return !(vtimer->cnt_ctl & ARCH_TIMER_CTRL_IT_MASK) &&
+   (vtimer->cnt_ctl & ARCH_TIMER_CTRL_ENABLE);
 }
 
 bool kvm_timer_should_fire(struct kvm_vcpu *vcpu)
 {
-   struct arch_timer_cpu *timer = >arch.timer_cpu;
+   struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
u64 cval, now;
 
if (!kvm_timer_irq_can_fire(vcpu))
return false;
 
-   cval = timer->cntv_cval;
+   cval = vtimer->cnt_cval;
now = kvm_phys_timer_read() - vcpu->kvm->arch.timer.cntvoff;
 
return cval <= now;
@@ -167,18 +167,18 @@ bool kvm_timer_should_fire(struct kvm_vcpu *vcpu)
 static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
 {
int ret;
-   struct arch_timer_cpu *timer = >arch.timer_cpu;
+   struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 
BUG_ON(!vgic_initialized(vcpu->kvm));
 
-   timer->active_cleared_last = false;
-   timer->irq.level = new_level;
-   trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->irq.irq,
-  timer->irq.level);
+   vtimer->active_cleared_last = false;
+   vtimer->irq.level = new_level;
+   trace_kvm_timer_update_irq(vcpu->vcpu_id, vtimer->irq.irq,
+  vtimer->irq.level);
 
ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
-timer->irq.irq,
-

[RFC v4 04/10] KVM: arm/arm64: Add the EL1 physical timer context

2017-02-03 Thread Jintack Lim
Add the EL1 physical timer context.

Signed-off-by: Jintack Lim <jint...@cs.columbia.edu>
Acked-by: Christoffer Dall <christoffer.d...@linaro.org>
---
 include/kvm/arm_arch_timer.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index f46fa3b..6445a3d 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -40,6 +40,7 @@ struct arch_timer_context {
 
 struct arch_timer_cpu {
struct arch_timer_context   vtimer;
+   struct arch_timer_context   ptimer;
 
/* Background timer used when the guest is not running */
struct hrtimer  timer;
@@ -75,4 +76,5 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
 void kvm_timer_init_vhe(void);
 
 #define vcpu_vtimer(v) (&(v)->arch.timer_cpu.vtimer)
+#define vcpu_ptimer(v) (&(v)->arch.timer_cpu.ptimer)
 #endif
-- 
1.9.1


___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


[RFC v4 00/10] Provide the EL1 physical timer to the VM

2017-02-03 Thread Jintack Lim
The ARM architecture defines the EL1 physical timer and the virtual timer,
and it is reasonable for an OS to expect to be able to access both.
However, the current KVM implementation does not provide the EL1 physical
timer to VMs but terminates VMs on access to the timer.

This patch series enables VMs to use the EL1 physical timer through
trap-and-emulate only on arm64. The KVM host emulates each EL1 physical
timer register access and sets up the background timer accordingly.  When
the background timer expires, the KVM host injects EL1 physical timer
interrupts to the VM.  Alternatively, it's also possible to allow VMs to
access the EL1 physical timer without trapping.  However, this requires
somehow using the EL2 physical timer for the Linux host while running the
VM instead of the EL1 physical timer.  Right now I just implemented
trap-and-emulate because this was straightforward to do, and I leave it to
future work to determine if transferring the EL1 physical timer state to
the EL2 timer provides any performance benefit.

This feature will be useful for any OS that wishes to access the EL1
physical timer. Nested virtualization is one of those use cases. A nested
hypervisor running inside a VM would think it has full access to the
hardware and naturally tries to use the EL1 physical timer as Linux would
do. Other nested hypervisors may try to use the EL2 physical timer as Xen
would do, but supporting the EL2 physical timer to the VM is out of scope
of this patch series. This patch series will make it easy to add the EL2
timer support in the future, though.

Note that Linux VMs booting in EL1 will be unaffected by this patch series
and will continue to use only the virtual timer and this patch series will
therefore not introduce any performance degredation as a result of
trap-and-emulate.

v3 => v4:
 - Fix a bug that prevents a VM from booting on 32-bit architecture
 - Clarify that the emulated physical timer is only supported on arm64
   in the cover letter

v2 => v3:
 - Rebase on kvmarm/queue
 - Take kvm->lock to synchronize cntvoff across all vtimers
 - Remove unnecessary function parameters
 - Add comments

v1 => v2:
 - Rebase on kvm-arm-for-4.10-rc4
 - To make it simple, schedule the background timer for the EL1 physical timer
   emulation on every entry to the VM and cancel it on exit.
 - Change timer_context structure to have cntvoff and restore enable field back
   to arch_timer_cpu structure
Jintack Lim (10):
  KVM: arm/arm64: Abstract virtual timer context into separate structure
  KVM: arm/arm64: Move cntvoff to each timer context
  KVM: arm/arm64: Decouple kvm timer functions from virtual timer
  KVM: arm/arm64: Add the EL1 physical timer context
  KVM: arm/arm64: Initialize the emulated EL1 physical timer
  KVM: arm/arm64: Update the physical timer interrupt level
  KVM: arm/arm64: Set a background timer to the earliest timer
expiration
  KVM: arm/arm64: Set up a background timer for the physical timer
emulation
  KVM: arm64: Add the EL1 physical timer access handler
  KVM: arm/arm64: Emulate the EL1 phys timer registers

 arch/arm/include/asm/kvm_host.h   |   3 -
 arch/arm/kvm/arm.c|   4 +-
 arch/arm/kvm/reset.c  |   9 +-
 arch/arm64/include/asm/kvm_host.h |   3 -
 arch/arm64/kvm/reset.c|   9 +-
 arch/arm64/kvm/sys_regs.c |  65 +
 include/kvm/arm_arch_timer.h  |  39 
 virt/kvm/arm/arch_timer.c | 200 ++
 virt/kvm/arm/hyp/timer-sr.c   |  13 +--
 9 files changed, 249 insertions(+), 96 deletions(-)

-- 
1.9.1


___
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm


Re: [RFC v3 00/10] Provide the EL1 physical timer to the VM

2017-02-03 Thread Jintack Lim
On Fri, Feb 3, 2017 at 7:33 AM, Christoffer Dall <cd...@linaro.org> wrote:
> On Thu, Feb 02, 2017 at 09:51:13AM -0500, Jintack Lim wrote:
>> On Thu, Feb 2, 2017 at 7:31 AM, Christoffer Dall <cd...@linaro.org> wrote:
>> > Hi Jintack,
>> >
>> > On Wed, Feb 01, 2017 at 12:43:00PM -0500, Jintack Lim wrote:
>> >> The ARM architecture defines the EL1 physical timer and the virtual timer,
>> >> and it is reasonable for an OS to expect to be able to access both.
>> >> However, the current KVM implementation does not provide the EL1 physical
>> >> timer to VMs but terminates VMs on access to the timer.
>> >>
>> >> This patch series enables VMs to use the EL1 physical timer through
>> >> trap-and-emulate.  The KVM host emulates each EL1 physical timer register
>> >> access and sets up the background timer accordingly.  When the background
>> >> timer expires, the KVM host injects EL1 physical timer interrupts to the
>> >> VM.  Alternatively, it's also possible to allow VMs to access the EL1
>> >> physical timer without trapping.  However, this requires somehow using the
>> >> EL2 physical timer for the Linux host while running the VM instead of the
>> >> EL1 physical timer.  Right now I just implemented trap-and-emulate because
>> >> this was straightforward to do, and I leave it to future work to determine
>> >> if transferring the EL1 physical timer state to the EL2 timer provides any
>> >> performance benefit.
>> >>
>> >> This feature will be useful for any OS that wishes to access the EL1
>> >> physical timer. Nested virtualization is one of those use cases. A nested
>> >> hypervisor running inside a VM would think it has full access to the
>> >> hardware and naturally tries to use the EL1 physical timer as Linux would
>> >> do. Other nested hypervisors may try to use the EL2 physical timer as Xen
>> >> would do, but supporting the EL2 physical timer to the VM is out of scope
>> >> of this patch series. This patch series will make it easy to add the EL2
>> >> timer support in the future, though.
>> >>
>> >> Note that Linux VMs booting in EL1 will be unaffected by this patch series
>> >> and will continue to use only the virtual timer and this patch series will
>> >> therefore not introduce any performance degredation as a result of
>> >> trap-and-emulate.
>> >>
>> >> v2 => v3:
>> >>  - Rebase on kvmarm/queue
>> >>  - Take kvm->lock to synchronize cntvoff across all vtimers
>> >>  - Remove unnecessary function parameters
>> >>  - Add comments
>> >
>> > I just gave v3 a test run on my TC2 (32-bit platform) and my guest
>> > quickly locks up trying to run cyclictest or when booting the machine it
>> > stalls with RCU timeouts.
>>
>> Ok. It's my fault not to specify that the emulated physical timer is
>> supported/tested on arm64.
>> On 32-bit platform, it is supposed to show the same behavior as
>> before, but I haven't tested.
>> Were you using the physical timer or the virtual timer for the guest?
>>
>> >
>> > Could you have a look?
>>
>> Sure, I'll have a look. I don't have access to my Cubietruck today,
>> but I can work on that tomorrow.
>>
>
> Don't bother, I've figured this out for you.

Thanks a lot.

>
> You need the following fixup to your patch:

Ok. I'll post v4 soon.
You've already do "acked-by" for this commit. Do I need to change it
to "signed-off-by"?

>
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index 93c811c..35d7100 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -410,14 +410,21 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
>  }
>
>  /* Make the updates of cntvoff for all vtimer contexts atomic */
> -static void update_vtimer_cntvoff(struct kvm *kvm, u64 cntvoff)
> +static void update_vtimer_cntvoff(struct kvm_vcpu *vcpu, u64 cntvoff)
>  {
> int i;
> -   struct kvm_vcpu *vcpu;
> +   struct kvm *kvm = vcpu->kvm;
> +   struct kvm_vcpu *tmp;
>
> mutex_lock(>lock);
> -   kvm_for_each_vcpu(i, vcpu, kvm)
> -   vcpu_vtimer(vcpu)->cntvoff = cntvoff;
> +   kvm_for_each_vcpu(i, tmp, kvm)
> +   vcpu_vtimer(tmp)->cntvoff = cntvoff;
> +
> +   /*
> +* When called from the vcpu create path, the CPU being created is not
> +* included in the loo

  1   2   3   >