Implement the PSCI specification (ARM DEN 0022A) to control virtual CPUs being "powered" on or off. 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.
Unified · Split
| @@ -2185,6 +2185,10 @@ return ENOEXEC for that vcpu. · 2184 unmodified lines | ||
| 2185 | 2185 | Note that because some registers reflect machine topology, all vcpus |
| 2186 | 2186 | should be created before this ioctl is invoked. |
| 2187 | 2187 | |
| 2188 | +Possible features: | |
| 2189 | + - KVM_ARM_VCPU_POWER_OFF: Starts the CPU in a power-off state. | |
| 2190 | + Depends on KVM_CAP_ARM_PSCI. | |
| 2191 | + | |
| 2188 | 2192 | |
| 2189 | 2193 | 4.78 KVM_GET_REG_LIST |
| 2190 | 2194 | |
| @@ -32,6 +32,11 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu); · 31 unmodified lines | ||
| 32 | 32 | void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr); |
| 33 | 33 | void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr); |
| 34 | 34 | |
| 35 | +static inline bool vcpu_mode_is_32bit(struct kvm_vcpu *vcpu) | |
| 36 | +{ | |
| 37 | + return 1; | |
| 38 | +} | |
| 39 | + | |
| 35 | 40 | static inline u32 *vcpu_pc(struct kvm_vcpu *vcpu) |
| 36 | 41 | { |
| 37 | 42 | return (u32 *)&vcpu->arch.regs.usr_regs.ARM_pc; |
| @@ -42,6 +47,11 @@ static inline u32 *vcpu_cpsr(struct kvm_vcpu *vcpu) · 4 unmodified lines | ||
| 42 | 47 | return (u32 *)&vcpu->arch.regs.usr_regs.ARM_cpsr; |
| 43 | 48 | } |
| 44 | 49 | |
| 50 | +static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu) | |
| 51 | +{ | |
| 52 | + *vcpu_cpsr(vcpu) |= PSR_T_BIT; | |
| 53 | +} | |
| 54 | + | |
| 45 | 55 | static inline bool mode_has_spsr(struct kvm_vcpu *vcpu) |
| 46 | 56 | { |
| 47 | 57 | unsigned long cpsr_mode = vcpu->arch.regs.usr_regs.ARM_cpsr & MODE_MASK; |
| @@ -30,7 +30,7 @@ · 29 unmodified lines | ||
| 30 | 30 | #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 |
| 31 | 31 | #define KVM_HAVE_ONE_REG |
| 32 | 32 | |
| 33 | −#define KVM_VCPU_MAX_FEATURES 0 | |
| 33 | +#define KVM_VCPU_MAX_FEATURES 1 | |
| 34 | 34 | |
| 35 | 35 | /* We don't currently support large pages. */ |
| 36 | 36 | #define KVM_HPAGE_GFN_SHIFT(x) 0 |
| @@ -100,6 +100,9 @@ struct kvm_vcpu_arch { · 63 unmodified lines | ||
| 100 | 100 | int last_pcpu; |
| 101 | 101 | cpumask_t require_dcache_flush; |
| 102 | 102 | |
| 103 | + /* Don't run the guest on this vcpu */ | |
| 104 | + bool pause; | |
| 105 | + | |
| 103 | 106 | /* IO related fields */ |
| 104 | 107 | struct kvm_decode mmio_decode; |
| 105 | 108 | |
| @@ -0,0 +1,23 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (C) 2012 - ARM Ltd | |
| 3 | + * Author: Marc Zyngier <marc.zyngier@arm.com> | |
| 4 | + * | |
| 5 | + * This program is free software; you can redistribute it and/or modify | |
| 6 | + * it under the terms of the GNU General Public License version 2 as | |
| 7 | + * published by the Free Software Foundation. | |
| 8 | + * | |
| 9 | + * This program is distributed in the hope that it will be useful, | |
| 10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + * GNU General Public License for more details. | |
| 13 | + * | |
| 14 | + * You should have received a copy of the GNU General Public License | |
| 15 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + */ | |
| 17 | + | |
| 18 | +#ifndef __ARM_KVM_PSCI_H__ | |
| 19 | +#define __ARM_KVM_PSCI_H__ | |
| 20 | + | |
| 21 | +bool kvm_psci_call(struct kvm_vcpu *vcpu); | |
| 22 | + | |
| 23 | +#endif /* __ARM_KVM_PSCI_H__ */ | |
| @@ -65,6 +65,8 @@ struct kvm_regs { · 64 unmodified lines | ||
| 65 | 65 | #define KVM_ARM_TARGET_CORTEX_A15 0 |
| 66 | 66 | #define KVM_ARM_NUM_TARGETS 1 |
| 67 | 67 | |
| 68 | +#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ | |
| 69 | + | |
| 68 | 70 | struct kvm_vcpu_init { |
| 69 | 71 | __u32 target; |
| 70 | 72 | __u32 features[7]; |
| @@ -145,4 +147,18 @@ struct kvm_arch_memory_slot { · 74 unmodified lines | ||
| 145 | 147 | /* Highest supported SPI, from VGIC_NR_IRQS */ |
| 146 | 148 | #define KVM_ARM_IRQ_GIC_MAX 127 |
| 147 | 149 | |
| 150 | +/* PSCI interface */ | |
| 151 | +#define KVM_PSCI_FN_BASE 0x95c1ba5e | |
| 152 | +#define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n)) | |
| 153 | + | |
| 154 | +#define KVM_PSCI_FN_CPU_SUSPEND KVM_PSCI_FN(0) | |
| 155 | +#define KVM_PSCI_FN_CPU_OFF KVM_PSCI_FN(1) | |
| 156 | +#define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2) | |
| 157 | +#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3) | |
| 158 | + | |
| 159 | +#define KVM_PSCI_RET_SUCCESS 0 | |
| 160 | +#define KVM_PSCI_RET_NI ((unsigned long)-1) | |
| 161 | +#define KVM_PSCI_RET_INVAL ((unsigned long)-2) | |
| 162 | +#define KVM_PSCI_RET_DENIED ((unsigned long)-3) | |
| 163 | + | |
| 148 | 164 | #endif /* __ARM_KVM_H__ */ |
| @@ -18,4 +18,4 @@ kvm-arm-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o) · 17 unmodified lines | ||
| 18 | 18 | |
| 19 | 19 | obj-y += kvm-arm.o init.o interrupts.o |
| 20 | 20 | obj-y += arm.o guest.o mmu.o emulate.o reset.o |
| 21 | −obj-y += coproc.o coproc_a15.o mmio.o | |
| 21 | +obj-y += coproc.o coproc_a15.o mmio.o psci.o | |
| @@ -43,6 +43,7 @@ · 42 unmodified lines | ||
| 43 | 43 | #include <asm/kvm_mmu.h> |
| 44 | 44 | #include <asm/kvm_emulate.h> |
| 45 | 45 | #include <asm/kvm_coproc.h> |
| 46 | +#include <asm/kvm_psci.h> | |
| 46 | 47 | #include <asm/opcodes.h> |
| 47 | 48 | |
| 48 | 49 | #ifdef REQUIRES_VIRT |
| @@ -160,6 +161,7 @@ int kvm_dev_ioctl_check_extension(long ext) · 111 unmodified lines | ||
| 160 | 161 | case KVM_CAP_SYNC_MMU: |
| 161 | 162 | case KVM_CAP_DESTROY_MEMORY_REGION_WORKS: |
| 162 | 163 | case KVM_CAP_ONE_REG: |
| 164 | + case KVM_CAP_ARM_PSCI: | |
| 163 | 165 | r = 1; |
| 164 | 166 | break; |
| 165 | 167 | case KVM_CAP_COALESCED_MMIO: |
| @@ -443,14 +445,18 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) · 277 unmodified lines | ||
| 443 | 445 | trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0), |
| 444 | 446 | vcpu->arch.hsr & HSR_HVC_IMM_MASK); |
| 445 | 447 | |
| 448 | + if (kvm_psci_call(vcpu)) | |
| 449 | + return 1; | |
| 450 | + | |
| 446 | 451 | kvm_inject_undefined(vcpu); |
| 447 | 452 | return 1; |
| 448 | 453 | } |
| 449 | 454 | |
| 450 | 455 | static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) |
| 451 | 456 | { |
| 452 | − /* We don't support SMC; don't do that. */ | |
| 453 | − kvm_debug("smc: at %08x", *vcpu_pc(vcpu)); | |
| 457 | + if (kvm_psci_call(vcpu)) | |
| 458 | + return 1; | |
| 459 | + | |
| 454 | 460 | kvm_inject_undefined(vcpu); |
| 455 | 461 | return 1; |
| 456 | 462 | } |
| @@ -589,9 +595,26 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu) · 132 unmodified lines | ||
| 589 | 595 | return 0; |
| 590 | 596 | |
| 591 | 597 | vcpu->arch.has_run_once = true; |
| 598 | + | |
| 599 | + /* | |
| 600 | + * Handle the "start in power-off" case by calling into the | |
| 601 | + * PSCI code. | |
| 602 | + */ | |
| 603 | + if (test_and_clear_bit(KVM_ARM_VCPU_POWER_OFF, vcpu->arch.features)) { | |
| 604 | + *vcpu_reg(vcpu, 0) = KVM_PSCI_FN_CPU_OFF; | |
| 605 | + kvm_psci_call(vcpu); | |
| 606 | + } | |
| 607 | + | |
| 592 | 608 | return 0; |
| 593 | 609 | } |
| 594 | 610 | |
| 611 | +static void vcpu_pause(struct kvm_vcpu *vcpu) | |
| 612 | +{ | |
| 613 | + wait_queue_head_t *wq = kvm_arch_vcpu_wq(vcpu); | |
| 614 | + | |
| 615 | + wait_event_interruptible(*wq, !vcpu->arch.pause); | |
| 616 | +} | |
| 617 | + | |
| 595 | 618 | /** |
| 596 | 619 | * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code |
| 597 | 620 | * @vcpu: The VCPU pointer |
| @@ -635,6 +658,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) · 37 unmodified lines | ||
| 635 | 658 | |
| 636 | 659 | update_vttbr(vcpu->kvm); |
| 637 | 660 | |
| 661 | + if (vcpu->arch.pause) | |
| 662 | + vcpu_pause(vcpu); | |
| 663 | + | |
| 638 | 664 | local_irq_disable(); |
| 639 | 665 | |
| 640 | 666 | /* |
| @@ -0,0 +1,108 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (C) 2012 - ARM Ltd | |
| 3 | + * Author: Marc Zyngier <marc.zyngier@arm.com> | |
| 4 | + * | |
| 5 | + * This program is free software; you can redistribute it and/or modify | |
| 6 | + * it under the terms of the GNU General Public License version 2 as | |
| 7 | + * published by the Free Software Foundation. | |
| 8 | + * | |
| 9 | + * This program is distributed in the hope that it will be useful, | |
| 10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + * GNU General Public License for more details. | |
| 13 | + * | |
| 14 | + * You should have received a copy of the GNU General Public License | |
| 15 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 16 | + */ | |
| 17 | + | |
| 18 | +#include <linux/kvm_host.h> | |
| 19 | +#include <linux/wait.h> | |
| 20 | + | |
| 21 | +#include <asm/kvm_emulate.h> | |
| 22 | +#include <asm/kvm_psci.h> | |
| 23 | + | |
| 24 | +/* | |
| 25 | + * This is an implementation of the Power State Coordination Interface | |
| 26 | + * as described in ARM document number ARM DEN 0022A. | |
| 27 | + */ | |
| 28 | + | |
| 29 | +static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu) | |
| 30 | +{ | |
| 31 | + vcpu->arch.pause = true; | |
| 32 | +} | |
| 33 | + | |
| 34 | +static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) | |
| 35 | +{ | |
| 36 | + struct kvm *kvm = source_vcpu->kvm; | |
| 37 | + struct kvm_vcpu *vcpu; | |
| 38 | + wait_queue_head_t *wq; | |
| 39 | + unsigned long cpu_id; | |
| 40 | + phys_addr_t target_pc; | |
| 41 | + | |
| 42 | + cpu_id = *vcpu_reg(source_vcpu, 1); | |
| 43 | + if (vcpu_mode_is_32bit(source_vcpu)) | |
| 44 | + cpu_id &= ~((u32) 0); | |
| 45 | + | |
| 46 | + if (cpu_id >= atomic_read(&kvm->online_vcpus)) | |
| 47 | + return KVM_PSCI_RET_INVAL; | |
| 48 | + | |
| 49 | + target_pc = *vcpu_reg(source_vcpu, 2); | |
| 50 | + | |
| 51 | + vcpu = kvm_get_vcpu(kvm, cpu_id); | |
| 52 | + | |
| 53 | + wq = kvm_arch_vcpu_wq(vcpu); | |
| 54 | + if (!waitqueue_active(wq)) | |
| 55 | + return KVM_PSCI_RET_INVAL; | |
| 56 | + | |
| 57 | + kvm_reset_vcpu(vcpu); | |
| 58 | + | |
| 59 | + /* Gracefully handle Thumb2 entry point */ | |
| 60 | + if (vcpu_mode_is_32bit(vcpu) && (target_pc & 1)) { | |
| 61 | + target_pc &= ~((phys_addr_t) 1); | |
| 62 | + vcpu_set_thumb(vcpu); | |
| 63 | + } | |
| 64 | + | |
| 65 | + *vcpu_pc(vcpu) = target_pc; | |
| 66 | + vcpu->arch.pause = false; | |
| 67 | + smp_mb(); /* Make sure the above is visible */ | |
| 68 | + | |
| 69 | + wake_up_interruptible(wq); | |
| 70 | + | |
| 71 | + return KVM_PSCI_RET_SUCCESS; | |
| 72 | +} | |
| 73 | + | |
| 74 | +/** | |
| 75 | + * kvm_psci_call - handle PSCI call if r0 value is in range | |
| 76 | + * @vcpu: Pointer to the VCPU struct | |
| 77 | + * | |
| 78 | + * Handle PSCI calls from guests through traps from HVC or SMC instructions. | |
| 79 | + * The calling convention is similar to SMC calls to the secure world where | |
| 80 | + * the function number is placed in r0 and this function returns true if the | |
| 81 | + * function number specified in r0 is withing the PSCI range, and false | |
| 82 | + * otherwise. | |
| 83 | + */ | |
| 84 | +bool kvm_psci_call(struct kvm_vcpu *vcpu) | |
| 85 | +{ | |
| 86 | + unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0); | |
| 87 | + unsigned long val; | |
| 88 | + | |
| 89 | + switch (psci_fn) { | |
| 90 | + case KVM_PSCI_FN_CPU_OFF: | |
| 91 | + kvm_psci_vcpu_off(vcpu); | |
| 92 | + val = KVM_PSCI_RET_SUCCESS; | |
| 93 | + break; | |
| 94 | + case KVM_PSCI_FN_CPU_ON: | |
| 95 | + val = kvm_psci_vcpu_on(vcpu); | |
| 96 | + break; | |
| 97 | + case KVM_PSCI_FN_CPU_SUSPEND: | |
| 98 | + case KVM_PSCI_FN_MIGRATE: | |
| 99 | + val = KVM_PSCI_RET_NI; | |
| 100 | + break; | |
| 101 | + | |
| 102 | + default: | |
| 103 | + return false; | |
| 104 | + } | |
| 105 | + | |
| 106 | + *vcpu_reg(vcpu, 0) = val; | |
| 107 | + return true; | |
| 108 | +} | |
| @@ -636,6 +636,7 @@ struct kvm_ppc_smmu_info { · 635 unmodified lines | ||
| 636 | 636 | #define KVM_CAP_IRQFD_RESAMPLE 82 |
| 637 | 637 | #define KVM_CAP_PPC_BOOKE_WATCHDOG 83 |
| 638 | 638 | #define KVM_CAP_PPC_HTAB_FD 84 |
| 639 | +#define KVM_CAP_ARM_PSCI 87 | |
| 639 | 640 | |
| 640 | 641 | #ifdef KVM_CAP_IRQ_ROUTING |
| 641 | 642 | |