Re: [PATCH] ARM: KVM: Power State Coordination Interface implementation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Jan 7, 2013 at 1:19 PM, Marc Zyngier <marc.zyngier@xxxxxxx> wrote:
> Implement the PSCI specification (ARM DEN 0022A) to control
> virtual CPUs being "powered" on or off.
>
> The PSCI/KVM is detected using the KVM_CAP_ARM_PSCI capability.
>
> A virtual CPU can now be initialized in a "powered off" state,
> using the KVM_ARM_VCPU_POWER_OFF feature flag.
>
> The guest can use either SMC or HVC to execute a PSCI function.
>
> Signed-off-by: Marc Zyngier <marc.zyngier@xxxxxxx>
> ---
>  arch/arm/include/asm/kvm_emulate.h |   5 ++
>  arch/arm/include/asm/kvm_host.h    |   2 +-
>  arch/arm/include/asm/kvm_psci.h    |  23 +++++++++
>  arch/arm/include/uapi/asm/kvm.h    |  16 ++++++
>  arch/arm/kvm/Makefile              |   2 +-
>  arch/arm/kvm/arm.c                 |  13 +++++
>  arch/arm/kvm/handle_exit.c         |  16 +++---
>  arch/arm/kvm/psci.c                | 103 +++++++++++++++++++++++++++++++++++++
>  include/uapi/linux/kvm.h           |   1 +
>  9 files changed, 170 insertions(+), 11 deletions(-)
>  create mode 100644 arch/arm/include/asm/kvm_psci.h
>  create mode 100644 arch/arm/kvm/psci.c
>
> diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
> index d52cb81..b6ed67b 100644
> --- a/arch/arm/include/asm/kvm_emulate.h
> +++ b/arch/arm/include/asm/kvm_emulate.h
> @@ -35,6 +35,11 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu);
>  void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
>  void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
>
> +static inline bool vcpu_mode_is_32bit(struct kvm_vcpu *vcpu)
> +{
> +       return 1;
> +}
> +

this looks premature

>  static inline unsigned long *vcpu_pc(struct kvm_vcpu *vcpu)
>  {
>         return &vcpu->arch.regs.usr_regs.ARM_pc;
> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
> index fe8153a..39fc844 100644
> --- a/arch/arm/include/asm/kvm_host.h
> +++ b/arch/arm/include/asm/kvm_host.h
> @@ -31,7 +31,7 @@
>  #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
>  #define KVM_HAVE_ONE_REG
>
> -#define KVM_VCPU_MAX_FEATURES 0
> +#define KVM_VCPU_MAX_FEATURES 1
>
>  /* We don't currently support large pages. */
>  #define KVM_HPAGE_GFN_SHIFT(x) 0
> diff --git a/arch/arm/include/asm/kvm_psci.h b/arch/arm/include/asm/kvm_psci.h
> new file mode 100644
> index 0000000..992d7f1
> --- /dev/null
> +++ b/arch/arm/include/asm/kvm_psci.h
> @@ -0,0 +1,23 @@
> +/*
> + * Copyright (C) 2012 - ARM Ltd
> + * Author: Marc Zyngier <marc.zyngier@xxxxxxx>
> + *
> + * 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/>.
> + */
> +
> +#ifndef __ARM_KVM_PSCI_H__
> +#define __ARM_KVM_PSCI_H__
> +
> +int kvm_psci_call(struct kvm_vcpu *vcpu);
> +
> +#endif /* __ARM_KVM_PSCI_H__ */
> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
> index 974f8b0..3c9663c 100644
> --- a/arch/arm/include/uapi/asm/kvm.h
> +++ b/arch/arm/include/uapi/asm/kvm.h
> @@ -81,6 +81,8 @@ struct kvm_regs {
>  #define KVM_VGIC_V2_DIST_SIZE          0x1000
>  #define KVM_VGIC_V2_CPU_SIZE           0x2000
>
> +#define KVM_ARM_VCPU_POWER_OFF         0 /* CPU is started in OFF state */
> +
>  struct kvm_vcpu_init {
>         __u32 target;
>         __u32 features[7];
> @@ -161,4 +163,18 @@ struct kvm_arch_memory_slot {
>  /* Highest supported SPI, from VGIC_NR_IRQS */
>  #define KVM_ARM_IRQ_GIC_MAX            127
>
> +/* PSCI interface */
> +#define KVM_PSCI_FN_BASE               0x95c1ba5e
> +#define KVM_PSCI_FN(n)                 (KVM_PSCI_FN_BASE + (n))
> +
> +#define KVM_PSCI_FN_CPU_SUSPEND                KVM_PSCI_FN(0)
> +#define KVM_PSCI_FN_CPU_OFF            KVM_PSCI_FN(1)
> +#define KVM_PSCI_FN_CPU_ON             KVM_PSCI_FN(2)
> +#define KVM_PSCI_FN_MIGRATE            KVM_PSCI_FN(3)
> +
> +#define KVM_PSCI_RET_SUCCESS           0
> +#define KVM_PSCI_RET_NI                        ((unsigned long)-1)
> +#define KVM_PSCI_RET_INVAL             ((unsigned long)-2)
> +#define KVM_PSCI_RET_DENIED            ((unsigned long)-3)
> +
>  #endif /* __ARM_KVM_H__ */
> diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
> index 81823c1..1974ba0 100644
> --- a/arch/arm/kvm/Makefile
> +++ b/arch/arm/kvm/Makefile
> @@ -18,6 +18,6 @@ kvm-arm-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o)
>
>  obj-y += kvm-arm.o init.o interrupts.o
>  obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
> -obj-y += coproc.o coproc_a15.o mmio.o decode.o
> +obj-y += coproc.o coproc_a15.o mmio.o decode.o psci.o
>  obj-$(CONFIG_KVM_ARM_VGIC) += vgic.o
>  obj-$(CONFIG_KVM_ARM_TIMER) += arch_timer.o
> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
> index d16712d..15e1700 100644
> --- a/arch/arm/kvm/arm.c
> +++ b/arch/arm/kvm/arm.c
> @@ -41,6 +41,7 @@
>  #include <asm/kvm_mmu.h>
>  #include <asm/kvm_emulate.h>
>  #include <asm/kvm_coproc.h>
> +#include <asm/kvm_psci.h>
>
>  #ifdef REQUIRES_VIRT
>  __asm__(".arch_extension       virt");
> @@ -189,6 +190,7 @@ int kvm_dev_ioctl_check_extension(long ext)
>         case KVM_CAP_SYNC_MMU:
>         case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
>         case KVM_CAP_ONE_REG:
> +       case KVM_CAP_ARM_PSCI:
>                 r = 1;
>                 break;
>         case KVM_CAP_COALESCED_MMIO:
> @@ -504,6 +506,17 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>                         return ret;
>         }
>
> +       /*
> +        * Handle the "start in power-off" case by calling into the
> +        * PSCI code. This only happens once in the lifetime of a
> +        * vcpu.
> +        */
> +       if (unlikely(test_and_clear_bit(KVM_ARM_VCPU_POWER_OFF,
> +                                       vcpu->arch.features))) {
> +               *vcpu_reg(vcpu, 0) = KVM_PSCI_FN_CPU_OFF;
> +               kvm_psci_call(vcpu);
> +       }
> +
>         if (vcpu->sigset_active)
>                 sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
>
> diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
> index f2fc5fa..de86710 100644
> --- a/arch/arm/kvm/handle_exit.c
> +++ b/arch/arm/kvm/handle_exit.c

this doesn't apply - looks like you sent a patch requiring your cleanup patches.

> @@ -21,6 +21,7 @@
>  #include <asm/kvm_emulate.h>
>  #include <asm/kvm_coproc.h>
>  #include <asm/kvm_mmu.h>
> +#include <asm/kvm_psci.h>
>  #include <trace/events/kvm.h>
>
>  #include "trace.h"
> @@ -37,21 +38,18 @@ static int handle_svc_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
>
>  static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  {
> -       /*
> -        * Guest called HVC instruction:
> -        * Let it know we don't want that by injecting an undefined exception.
> -        */
> -       kvm_debug("hvc: %x (at %08lx)", kvm_vcpu_get_hsr(vcpu) & ((1 << 16) - 1),
> -                 *vcpu_pc(vcpu));
> -       kvm_debug("         HSR: %8x", kvm_vcpu_get_hsr(vcpu));
> +       if (!kvm_psci_call(vcpu))
> +               return 1;
> +
>         kvm_inject_undefined(vcpu);
>         return 1;
>  }
>
>  static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  {
> -       /* We don't support SMC; don't do that. */
> -       kvm_debug("smc: at %08lx", *vcpu_pc(vcpu));
> +       if (!kvm_psci_call(vcpu))
> +               return 1;
> +
>         kvm_inject_undefined(vcpu);
>         return 1;
>  }
> diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c
> new file mode 100644
> index 0000000..d59f763
> --- /dev/null
> +++ b/arch/arm/kvm/psci.c
> @@ -0,0 +1,103 @@
> +/*
> + * Copyright (C) 2012 - ARM Ltd
> + * Author: Marc Zyngier <marc.zyngier@xxxxxxx>
> + *
> + * 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 <linux/kvm_host.h>
> +#include <linux/sched.h>
> +
> +#include <asm/kvm_emulate.h>
> +#include <asm/kvm_psci.h>
> +
> +static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu)
> +{
> +       DEFINE_WAIT(wait);
> +       wait_queue_head_t *wq = kvm_arch_vcpu_wq(vcpu);
> +
> +       vcpu->arch.pause = true;
> +
> +       while (1) {
> +               prepare_to_wait(wq, &wait, TASK_INTERRUPTIBLE);
> +
> +               if (!vcpu->arch.pause)
> +                       break;
> +
> +               if (signal_pending(current))
> +                       break;
> +
> +               schedule();
> +       };
> +
> +       finish_wait(wq, &wait);
> +}
> +
> +static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
> +{
> +       struct kvm *kvm = source_vcpu->kvm;
> +       struct kvm_vcpu *vcpu;
> +       wait_queue_head_t *wq;
> +       unsigned long cpu_id;
> +       phys_addr_t target_pc;
> +
> +       cpu_id = *vcpu_reg(source_vcpu, 1);
> +       if (vcpu_mode_is_32bit(source_vcpu))
> +               cpu_id &= ~((u32) 0);
> +
> +       if (cpu_id >= atomic_read(&kvm->online_vcpus))
> +               return KVM_PSCI_RET_INVAL;
> +
> +       target_pc = *vcpu_reg(source_vcpu, 2);
> +
> +       vcpu = kvm_get_vcpu(kvm, cpu_id);
> +
> +       wq = kvm_arch_vcpu_wq(vcpu);
> +       if (!waitqueue_active(wq))
> +               return KVM_PSCI_RET_INVAL;
> +
> +       kvm_reset_vcpu(vcpu);
> +       *vcpu_pc(vcpu) = target_pc;
> +       vcpu->arch.pause = false;
> +       smp_mb();               /* Make sure the above is visible */
> +
> +       wake_up_interruptible(wq);
> +
> +       return KVM_PSCI_RET_SUCCESS;
> +}
> +
> +int kvm_psci_call(struct kvm_vcpu *vcpu)
> +{
> +       unsigned long psci_fn = *vcpu_reg(vcpu, 0) & 0xffffffff;
> +       unsigned long val;
> +
> +       switch (psci_fn) {
> +       case KVM_PSCI_FN_CPU_OFF:
> +               kvm_psci_vcpu_off(vcpu);
> +               val = KVM_PSCI_RET_SUCCESS;
> +               break;
> +       case KVM_PSCI_FN_CPU_ON:
> +               val = kvm_psci_vcpu_on(vcpu);
> +               break;
> +       case KVM_PSCI_FN_CPU_SUSPEND:
> +       case KVM_PSCI_FN_MIGRATE:
> +               val = KVM_PSCI_RET_NI;
> +               break;
> +
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       *vcpu_reg(vcpu, 0) = val;
> +       return 0;
> +}
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 03248d1..8233566 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -637,6 +637,7 @@ struct kvm_ppc_smmu_info {
>  #define KVM_CAP_PPC_BOOKE_WATCHDOG 83
>  #define KVM_CAP_PPC_HTAB_FD 84
>  #define KVM_CAP_SET_DEVICE_ADDR 85
> +#define KVM_CAP_ARM_PSCI 86
>
>  #ifdef KVM_CAP_IRQ_ROUTING
>
> --
> 1.8.1
>
>
>
> _______________________________________________
> kvmarm mailing list
> kvmarm@xxxxxxxxxxxxxxxxxxxxx
> https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm
_______________________________________________
kvmarm mailing list
kvmarm@xxxxxxxxxxxxxxxxxxxxx
https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm


[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux