You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'kvm-arm-for-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into 'kvm-next'
KVM/ARM changes for v4.1: - fixes for live migration - irqfd support - kvm-io-bus & vgic rework to enable ioeventfd - page ageing for stage-2 translation - various cleanups
This commit is contained in:
@@ -997,7 +997,7 @@ for vm-wide capabilities.
|
|||||||
4.38 KVM_GET_MP_STATE
|
4.38 KVM_GET_MP_STATE
|
||||||
|
|
||||||
Capability: KVM_CAP_MP_STATE
|
Capability: KVM_CAP_MP_STATE
|
||||||
Architectures: x86, s390
|
Architectures: x86, s390, arm, arm64
|
||||||
Type: vcpu ioctl
|
Type: vcpu ioctl
|
||||||
Parameters: struct kvm_mp_state (out)
|
Parameters: struct kvm_mp_state (out)
|
||||||
Returns: 0 on success; -1 on error
|
Returns: 0 on success; -1 on error
|
||||||
@@ -1011,7 +1011,7 @@ uniprocessor guests).
|
|||||||
|
|
||||||
Possible values are:
|
Possible values are:
|
||||||
|
|
||||||
- KVM_MP_STATE_RUNNABLE: the vcpu is currently running [x86]
|
- KVM_MP_STATE_RUNNABLE: the vcpu is currently running [x86,arm/arm64]
|
||||||
- KVM_MP_STATE_UNINITIALIZED: the vcpu is an application processor (AP)
|
- KVM_MP_STATE_UNINITIALIZED: the vcpu is an application processor (AP)
|
||||||
which has not yet received an INIT signal [x86]
|
which has not yet received an INIT signal [x86]
|
||||||
- KVM_MP_STATE_INIT_RECEIVED: the vcpu has received an INIT signal, and is
|
- KVM_MP_STATE_INIT_RECEIVED: the vcpu has received an INIT signal, and is
|
||||||
@@ -1020,7 +1020,7 @@ Possible values are:
|
|||||||
is waiting for an interrupt [x86]
|
is waiting for an interrupt [x86]
|
||||||
- KVM_MP_STATE_SIPI_RECEIVED: the vcpu has just received a SIPI (vector
|
- KVM_MP_STATE_SIPI_RECEIVED: the vcpu has just received a SIPI (vector
|
||||||
accessible via KVM_GET_VCPU_EVENTS) [x86]
|
accessible via KVM_GET_VCPU_EVENTS) [x86]
|
||||||
- KVM_MP_STATE_STOPPED: the vcpu is stopped [s390]
|
- KVM_MP_STATE_STOPPED: the vcpu is stopped [s390,arm/arm64]
|
||||||
- KVM_MP_STATE_CHECK_STOP: the vcpu is in a special error state [s390]
|
- KVM_MP_STATE_CHECK_STOP: the vcpu is in a special error state [s390]
|
||||||
- KVM_MP_STATE_OPERATING: the vcpu is operating (running or halted)
|
- KVM_MP_STATE_OPERATING: the vcpu is operating (running or halted)
|
||||||
[s390]
|
[s390]
|
||||||
@@ -1031,11 +1031,15 @@ On x86, this ioctl is only useful after KVM_CREATE_IRQCHIP. Without an
|
|||||||
in-kernel irqchip, the multiprocessing state must be maintained by userspace on
|
in-kernel irqchip, the multiprocessing state must be maintained by userspace on
|
||||||
these architectures.
|
these architectures.
|
||||||
|
|
||||||
|
For arm/arm64:
|
||||||
|
|
||||||
|
The only states that are valid are KVM_MP_STATE_STOPPED and
|
||||||
|
KVM_MP_STATE_RUNNABLE which reflect if the vcpu is paused or not.
|
||||||
|
|
||||||
4.39 KVM_SET_MP_STATE
|
4.39 KVM_SET_MP_STATE
|
||||||
|
|
||||||
Capability: KVM_CAP_MP_STATE
|
Capability: KVM_CAP_MP_STATE
|
||||||
Architectures: x86, s390
|
Architectures: x86, s390, arm, arm64
|
||||||
Type: vcpu ioctl
|
Type: vcpu ioctl
|
||||||
Parameters: struct kvm_mp_state (in)
|
Parameters: struct kvm_mp_state (in)
|
||||||
Returns: 0 on success; -1 on error
|
Returns: 0 on success; -1 on error
|
||||||
@@ -1047,6 +1051,10 @@ On x86, this ioctl is only useful after KVM_CREATE_IRQCHIP. Without an
|
|||||||
in-kernel irqchip, the multiprocessing state must be maintained by userspace on
|
in-kernel irqchip, the multiprocessing state must be maintained by userspace on
|
||||||
these architectures.
|
these architectures.
|
||||||
|
|
||||||
|
For arm/arm64:
|
||||||
|
|
||||||
|
The only states that are valid are KVM_MP_STATE_STOPPED and
|
||||||
|
KVM_MP_STATE_RUNNABLE which reflect if the vcpu should be paused or not.
|
||||||
|
|
||||||
4.40 KVM_SET_IDENTITY_MAP_ADDR
|
4.40 KVM_SET_IDENTITY_MAP_ADDR
|
||||||
|
|
||||||
@@ -2263,7 +2271,7 @@ into the hash PTE second double word).
|
|||||||
4.75 KVM_IRQFD
|
4.75 KVM_IRQFD
|
||||||
|
|
||||||
Capability: KVM_CAP_IRQFD
|
Capability: KVM_CAP_IRQFD
|
||||||
Architectures: x86 s390
|
Architectures: x86 s390 arm arm64
|
||||||
Type: vm ioctl
|
Type: vm ioctl
|
||||||
Parameters: struct kvm_irqfd (in)
|
Parameters: struct kvm_irqfd (in)
|
||||||
Returns: 0 on success, -1 on error
|
Returns: 0 on success, -1 on error
|
||||||
@@ -2289,6 +2297,10 @@ Note that closing the resamplefd is not sufficient to disable the
|
|||||||
irqfd. The KVM_IRQFD_FLAG_RESAMPLE is only necessary on assignment
|
irqfd. The KVM_IRQFD_FLAG_RESAMPLE is only necessary on assignment
|
||||||
and need not be specified with KVM_IRQFD_FLAG_DEASSIGN.
|
and need not be specified with KVM_IRQFD_FLAG_DEASSIGN.
|
||||||
|
|
||||||
|
On ARM/ARM64, the gsi field in the kvm_irqfd struct specifies the Shared
|
||||||
|
Peripheral Interrupt (SPI) index, such that the GIC interrupt ID is
|
||||||
|
given by gsi + 32.
|
||||||
|
|
||||||
4.76 KVM_PPC_ALLOCATE_HTAB
|
4.76 KVM_PPC_ALLOCATE_HTAB
|
||||||
|
|
||||||
Capability: KVM_CAP_PPC_ALLOC_HTAB
|
Capability: KVM_CAP_PPC_ALLOC_HTAB
|
||||||
|
|||||||
@@ -185,6 +185,7 @@
|
|||||||
#define HSR_COND (0xfU << HSR_COND_SHIFT)
|
#define HSR_COND (0xfU << HSR_COND_SHIFT)
|
||||||
|
|
||||||
#define FSC_FAULT (0x04)
|
#define FSC_FAULT (0x04)
|
||||||
|
#define FSC_ACCESS (0x08)
|
||||||
#define FSC_PERM (0x0c)
|
#define FSC_PERM (0x0c)
|
||||||
|
|
||||||
/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
|
/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
#include <asm/fpstate.h>
|
#include <asm/fpstate.h>
|
||||||
#include <kvm/arm_arch_timer.h>
|
#include <kvm/arm_arch_timer.h>
|
||||||
|
|
||||||
|
#define __KVM_HAVE_ARCH_INTC_INITIALIZED
|
||||||
|
|
||||||
#if defined(CONFIG_KVM_ARM_MAX_VCPUS)
|
#if defined(CONFIG_KVM_ARM_MAX_VCPUS)
|
||||||
#define KVM_MAX_VCPUS CONFIG_KVM_ARM_MAX_VCPUS
|
#define KVM_MAX_VCPUS CONFIG_KVM_ARM_MAX_VCPUS
|
||||||
#else
|
#else
|
||||||
@@ -165,19 +167,10 @@ void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
|
|||||||
|
|
||||||
unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
|
unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
|
||||||
int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
|
int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
|
||||||
|
int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
|
||||||
|
int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
|
||||||
|
|
||||||
/* We do not have shadow page tables, hence the empty hooks */
|
/* We do not have shadow page tables, hence the empty hooks */
|
||||||
static inline int kvm_age_hva(struct kvm *kvm, unsigned long start,
|
|
||||||
unsigned long end)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
|
static inline void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
|
||||||
unsigned long address)
|
unsigned long address)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,28 +28,6 @@ struct kvm_decode {
|
|||||||
bool sign_extend;
|
bool sign_extend;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* The in-kernel MMIO emulation code wants to use a copy of run->mmio,
|
|
||||||
* which is an anonymous type. Use our own type instead.
|
|
||||||
*/
|
|
||||||
struct kvm_exit_mmio {
|
|
||||||
phys_addr_t phys_addr;
|
|
||||||
u8 data[8];
|
|
||||||
u32 len;
|
|
||||||
bool is_write;
|
|
||||||
void *private;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline void kvm_prepare_mmio(struct kvm_run *run,
|
|
||||||
struct kvm_exit_mmio *mmio)
|
|
||||||
{
|
|
||||||
run->mmio.phys_addr = mmio->phys_addr;
|
|
||||||
run->mmio.len = mmio->len;
|
|
||||||
run->mmio.is_write = mmio->is_write;
|
|
||||||
memcpy(run->mmio.data, mmio->data, mmio->len);
|
|
||||||
run->exit_reason = KVM_EXIT_MMIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||||
int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
||||||
phys_addr_t fault_ipa);
|
phys_addr_t fault_ipa);
|
||||||
|
|||||||
@@ -198,6 +198,9 @@ struct kvm_arch_memory_slot {
|
|||||||
/* Highest supported SPI, from VGIC_NR_IRQS */
|
/* Highest supported SPI, from VGIC_NR_IRQS */
|
||||||
#define KVM_ARM_IRQ_GIC_MAX 127
|
#define KVM_ARM_IRQ_GIC_MAX 127
|
||||||
|
|
||||||
|
/* One single KVM irqchip, ie. the VGIC */
|
||||||
|
#define KVM_NR_IRQCHIPS 1
|
||||||
|
|
||||||
/* PSCI interface */
|
/* PSCI interface */
|
||||||
#define KVM_PSCI_FN_BASE 0x95c1ba5e
|
#define KVM_PSCI_FN_BASE 0x95c1ba5e
|
||||||
#define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n))
|
#define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n))
|
||||||
|
|||||||
@@ -190,7 +190,6 @@ int main(void)
|
|||||||
DEFINE(VCPU_HxFAR, offsetof(struct kvm_vcpu, arch.fault.hxfar));
|
DEFINE(VCPU_HxFAR, offsetof(struct kvm_vcpu, arch.fault.hxfar));
|
||||||
DEFINE(VCPU_HPFAR, offsetof(struct kvm_vcpu, arch.fault.hpfar));
|
DEFINE(VCPU_HPFAR, offsetof(struct kvm_vcpu, arch.fault.hpfar));
|
||||||
DEFINE(VCPU_HYP_PC, offsetof(struct kvm_vcpu, arch.fault.hyp_pc));
|
DEFINE(VCPU_HYP_PC, offsetof(struct kvm_vcpu, arch.fault.hyp_pc));
|
||||||
#ifdef CONFIG_KVM_ARM_VGIC
|
|
||||||
DEFINE(VCPU_VGIC_CPU, offsetof(struct kvm_vcpu, arch.vgic_cpu));
|
DEFINE(VCPU_VGIC_CPU, offsetof(struct kvm_vcpu, arch.vgic_cpu));
|
||||||
DEFINE(VGIC_V2_CPU_HCR, offsetof(struct vgic_cpu, vgic_v2.vgic_hcr));
|
DEFINE(VGIC_V2_CPU_HCR, offsetof(struct vgic_cpu, vgic_v2.vgic_hcr));
|
||||||
DEFINE(VGIC_V2_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v2.vgic_vmcr));
|
DEFINE(VGIC_V2_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v2.vgic_vmcr));
|
||||||
@@ -200,14 +199,11 @@ int main(void)
|
|||||||
DEFINE(VGIC_V2_CPU_APR, offsetof(struct vgic_cpu, vgic_v2.vgic_apr));
|
DEFINE(VGIC_V2_CPU_APR, offsetof(struct vgic_cpu, vgic_v2.vgic_apr));
|
||||||
DEFINE(VGIC_V2_CPU_LR, offsetof(struct vgic_cpu, vgic_v2.vgic_lr));
|
DEFINE(VGIC_V2_CPU_LR, offsetof(struct vgic_cpu, vgic_v2.vgic_lr));
|
||||||
DEFINE(VGIC_CPU_NR_LR, offsetof(struct vgic_cpu, nr_lr));
|
DEFINE(VGIC_CPU_NR_LR, offsetof(struct vgic_cpu, nr_lr));
|
||||||
#ifdef CONFIG_KVM_ARM_TIMER
|
|
||||||
DEFINE(VCPU_TIMER_CNTV_CTL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_ctl));
|
DEFINE(VCPU_TIMER_CNTV_CTL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_ctl));
|
||||||
DEFINE(VCPU_TIMER_CNTV_CVAL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_cval));
|
DEFINE(VCPU_TIMER_CNTV_CVAL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_cval));
|
||||||
DEFINE(KVM_TIMER_CNTVOFF, offsetof(struct kvm, arch.timer.cntvoff));
|
DEFINE(KVM_TIMER_CNTVOFF, offsetof(struct kvm, arch.timer.cntvoff));
|
||||||
DEFINE(KVM_TIMER_ENABLED, offsetof(struct kvm, arch.timer.enabled));
|
DEFINE(KVM_TIMER_ENABLED, offsetof(struct kvm, arch.timer.enabled));
|
||||||
#endif
|
|
||||||
DEFINE(KVM_VGIC_VCTRL, offsetof(struct kvm, arch.vgic.vctrl_base));
|
DEFINE(KVM_VGIC_VCTRL, offsetof(struct kvm, arch.vgic.vctrl_base));
|
||||||
#endif
|
|
||||||
DEFINE(KVM_VTTBR, offsetof(struct kvm, arch.vttbr));
|
DEFINE(KVM_VTTBR, offsetof(struct kvm, arch.vttbr));
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+7
-23
@@ -18,6 +18,7 @@ if VIRTUALIZATION
|
|||||||
|
|
||||||
config KVM
|
config KVM
|
||||||
bool "Kernel-based Virtual Machine (KVM) support"
|
bool "Kernel-based Virtual Machine (KVM) support"
|
||||||
|
depends on MMU && OF
|
||||||
select PREEMPT_NOTIFIERS
|
select PREEMPT_NOTIFIERS
|
||||||
select ANON_INODES
|
select ANON_INODES
|
||||||
select HAVE_KVM_CPU_RELAX_INTERCEPT
|
select HAVE_KVM_CPU_RELAX_INTERCEPT
|
||||||
@@ -26,10 +27,12 @@ config KVM
|
|||||||
select KVM_ARM_HOST
|
select KVM_ARM_HOST
|
||||||
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
|
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
|
||||||
select SRCU
|
select SRCU
|
||||||
depends on ARM_VIRT_EXT && ARM_LPAE
|
select MMU_NOTIFIER
|
||||||
|
select HAVE_KVM_EVENTFD
|
||||||
|
select HAVE_KVM_IRQFD
|
||||||
|
depends on ARM_VIRT_EXT && ARM_LPAE && ARM_ARCH_TIMER
|
||||||
---help---
|
---help---
|
||||||
Support hosting virtualized guest machines. You will also
|
Support hosting virtualized guest machines.
|
||||||
need to select one or more of the processor modules below.
|
|
||||||
|
|
||||||
This module provides access to the hardware capabilities through
|
This module provides access to the hardware capabilities through
|
||||||
a character device node named /dev/kvm.
|
a character device node named /dev/kvm.
|
||||||
@@ -37,10 +40,7 @@ config KVM
|
|||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
config KVM_ARM_HOST
|
config KVM_ARM_HOST
|
||||||
bool "KVM host support for ARM cpus."
|
bool
|
||||||
depends on KVM
|
|
||||||
depends on MMU
|
|
||||||
select MMU_NOTIFIER
|
|
||||||
---help---
|
---help---
|
||||||
Provides host support for ARM processors.
|
Provides host support for ARM processors.
|
||||||
|
|
||||||
@@ -55,20 +55,4 @@ config KVM_ARM_MAX_VCPUS
|
|||||||
large, so only choose a reasonable number that you expect to
|
large, so only choose a reasonable number that you expect to
|
||||||
actually use.
|
actually use.
|
||||||
|
|
||||||
config KVM_ARM_VGIC
|
|
||||||
bool "KVM support for Virtual GIC"
|
|
||||||
depends on KVM_ARM_HOST && OF
|
|
||||||
select HAVE_KVM_IRQCHIP
|
|
||||||
default y
|
|
||||||
---help---
|
|
||||||
Adds support for a hardware assisted, in-kernel GIC emulation.
|
|
||||||
|
|
||||||
config KVM_ARM_TIMER
|
|
||||||
bool "KVM support for Architected Timers"
|
|
||||||
depends on KVM_ARM_VGIC && ARM_ARCH_TIMER
|
|
||||||
select HAVE_KVM_IRQCHIP
|
|
||||||
default y
|
|
||||||
---help---
|
|
||||||
Adds support for the Architected Timers in virtual machines
|
|
||||||
|
|
||||||
endif # VIRTUALIZATION
|
endif # VIRTUALIZATION
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ ifeq ($(plus_virt),+virt)
|
|||||||
plus_virt_def := -DREQUIRES_VIRT=1
|
plus_virt_def := -DREQUIRES_VIRT=1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ccflags-y += -Ivirt/kvm -Iarch/arm/kvm
|
ccflags-y += -Iarch/arm/kvm
|
||||||
CFLAGS_arm.o := -I. $(plus_virt_def)
|
CFLAGS_arm.o := -I. $(plus_virt_def)
|
||||||
CFLAGS_mmu.o := -I.
|
CFLAGS_mmu.o := -I.
|
||||||
|
|
||||||
@@ -15,12 +15,12 @@ AFLAGS_init.o := -Wa,-march=armv7-a$(plus_virt)
|
|||||||
AFLAGS_interrupts.o := -Wa,-march=armv7-a$(plus_virt)
|
AFLAGS_interrupts.o := -Wa,-march=armv7-a$(plus_virt)
|
||||||
|
|
||||||
KVM := ../../../virt/kvm
|
KVM := ../../../virt/kvm
|
||||||
kvm-arm-y = $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o
|
kvm-arm-y = $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o
|
||||||
|
|
||||||
obj-y += kvm-arm.o init.o interrupts.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 += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
|
||||||
obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o
|
obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o
|
||||||
obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o
|
obj-y += $(KVM)/arm/vgic.o
|
||||||
obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o
|
obj-y += $(KVM)/arm/vgic-v2.o
|
||||||
obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2-emul.o
|
obj-y += $(KVM)/arm/vgic-v2-emul.o
|
||||||
obj-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o
|
obj-y += $(KVM)/arm/arch_timer.o
|
||||||
|
|||||||
+28
-17
@@ -61,8 +61,6 @@ static atomic64_t kvm_vmid_gen = ATOMIC64_INIT(1);
|
|||||||
static u8 kvm_next_vmid;
|
static u8 kvm_next_vmid;
|
||||||
static DEFINE_SPINLOCK(kvm_vmid_lock);
|
static DEFINE_SPINLOCK(kvm_vmid_lock);
|
||||||
|
|
||||||
static bool vgic_present;
|
|
||||||
|
|
||||||
static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
|
static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
BUG_ON(preemptible());
|
BUG_ON(preemptible());
|
||||||
@@ -173,8 +171,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
|||||||
int r;
|
int r;
|
||||||
switch (ext) {
|
switch (ext) {
|
||||||
case KVM_CAP_IRQCHIP:
|
case KVM_CAP_IRQCHIP:
|
||||||
r = vgic_present;
|
case KVM_CAP_IRQFD:
|
||||||
break;
|
case KVM_CAP_IOEVENTFD:
|
||||||
case KVM_CAP_DEVICE_CTRL:
|
case KVM_CAP_DEVICE_CTRL:
|
||||||
case KVM_CAP_USER_MEMORY:
|
case KVM_CAP_USER_MEMORY:
|
||||||
case KVM_CAP_SYNC_MMU:
|
case KVM_CAP_SYNC_MMU:
|
||||||
@@ -183,6 +181,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
|||||||
case KVM_CAP_ARM_PSCI:
|
case KVM_CAP_ARM_PSCI:
|
||||||
case KVM_CAP_ARM_PSCI_0_2:
|
case KVM_CAP_ARM_PSCI_0_2:
|
||||||
case KVM_CAP_READONLY_MEM:
|
case KVM_CAP_READONLY_MEM:
|
||||||
|
case KVM_CAP_MP_STATE:
|
||||||
r = 1;
|
r = 1;
|
||||||
break;
|
break;
|
||||||
case KVM_CAP_COALESCED_MMIO:
|
case KVM_CAP_COALESCED_MMIO:
|
||||||
@@ -268,7 +267,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
|
|||||||
|
|
||||||
int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
|
int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
return 0;
|
return kvm_timer_should_fire(vcpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
|
int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
|
||||||
@@ -313,13 +312,29 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
|
|||||||
int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
|
int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
|
||||||
struct kvm_mp_state *mp_state)
|
struct kvm_mp_state *mp_state)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
if (vcpu->arch.pause)
|
||||||
|
mp_state->mp_state = KVM_MP_STATE_STOPPED;
|
||||||
|
else
|
||||||
|
mp_state->mp_state = KVM_MP_STATE_RUNNABLE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
|
int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
|
||||||
struct kvm_mp_state *mp_state)
|
struct kvm_mp_state *mp_state)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
switch (mp_state->mp_state) {
|
||||||
|
case KVM_MP_STATE_RUNNABLE:
|
||||||
|
vcpu->arch.pause = false;
|
||||||
|
break;
|
||||||
|
case KVM_MP_STATE_STOPPED:
|
||||||
|
vcpu->arch.pause = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -452,6 +467,11 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool kvm_arch_intc_initialized(struct kvm *kvm)
|
||||||
|
{
|
||||||
|
return vgic_initialized(kvm);
|
||||||
|
}
|
||||||
|
|
||||||
static void vcpu_pause(struct kvm_vcpu *vcpu)
|
static void vcpu_pause(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
wait_queue_head_t *wq = kvm_arch_vcpu_wq(vcpu);
|
wait_queue_head_t *wq = kvm_arch_vcpu_wq(vcpu);
|
||||||
@@ -831,8 +851,6 @@ static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
|
|||||||
|
|
||||||
switch (dev_id) {
|
switch (dev_id) {
|
||||||
case KVM_ARM_DEVICE_VGIC_V2:
|
case KVM_ARM_DEVICE_VGIC_V2:
|
||||||
if (!vgic_present)
|
|
||||||
return -ENXIO;
|
|
||||||
return kvm_vgic_addr(kvm, type, &dev_addr->addr, true);
|
return kvm_vgic_addr(kvm, type, &dev_addr->addr, true);
|
||||||
default:
|
default:
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
@@ -847,10 +865,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
|
|||||||
|
|
||||||
switch (ioctl) {
|
switch (ioctl) {
|
||||||
case KVM_CREATE_IRQCHIP: {
|
case KVM_CREATE_IRQCHIP: {
|
||||||
if (vgic_present)
|
return kvm_vgic_create(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);
|
||||||
return kvm_vgic_create(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);
|
|
||||||
else
|
|
||||||
return -ENXIO;
|
|
||||||
}
|
}
|
||||||
case KVM_ARM_SET_DEVICE_ADDR: {
|
case KVM_ARM_SET_DEVICE_ADDR: {
|
||||||
struct kvm_arm_device_addr dev_addr;
|
struct kvm_arm_device_addr dev_addr;
|
||||||
@@ -1035,10 +1050,6 @@ static int init_hyp_mode(void)
|
|||||||
if (err)
|
if (err)
|
||||||
goto out_free_context;
|
goto out_free_context;
|
||||||
|
|
||||||
#ifdef CONFIG_KVM_ARM_VGIC
|
|
||||||
vgic_present = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Init HYP architected timer support
|
* Init HYP architected timer support
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -109,22 +109,6 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_KVM_ARM_TIMER
|
|
||||||
|
|
||||||
#define NUM_TIMER_REGS 0
|
|
||||||
|
|
||||||
static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_timer_reg(u64 index)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define NUM_TIMER_REGS 3
|
#define NUM_TIMER_REGS 3
|
||||||
|
|
||||||
static bool is_timer_reg(u64 index)
|
static bool is_timer_reg(u64 index)
|
||||||
@@ -152,8 +136,6 @@ static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int set_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
static int set_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
|
||||||
{
|
{
|
||||||
void __user *uaddr = (void __user *)(long)reg->addr;
|
void __user *uaddr = (void __user *)(long)reg->addr;
|
||||||
|
|||||||
@@ -402,7 +402,6 @@ vcpu .req r0 @ vcpu pointer always in r0
|
|||||||
* Assumes vcpu pointer in vcpu reg
|
* Assumes vcpu pointer in vcpu reg
|
||||||
*/
|
*/
|
||||||
.macro save_vgic_state
|
.macro save_vgic_state
|
||||||
#ifdef CONFIG_KVM_ARM_VGIC
|
|
||||||
/* Get VGIC VCTRL base into r2 */
|
/* Get VGIC VCTRL base into r2 */
|
||||||
ldr r2, [vcpu, #VCPU_KVM]
|
ldr r2, [vcpu, #VCPU_KVM]
|
||||||
ldr r2, [r2, #KVM_VGIC_VCTRL]
|
ldr r2, [r2, #KVM_VGIC_VCTRL]
|
||||||
@@ -460,7 +459,6 @@ ARM_BE8(rev r6, r6 )
|
|||||||
subs r4, r4, #1
|
subs r4, r4, #1
|
||||||
bne 1b
|
bne 1b
|
||||||
2:
|
2:
|
||||||
#endif
|
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -469,7 +467,6 @@ ARM_BE8(rev r6, r6 )
|
|||||||
* Assumes vcpu pointer in vcpu reg
|
* Assumes vcpu pointer in vcpu reg
|
||||||
*/
|
*/
|
||||||
.macro restore_vgic_state
|
.macro restore_vgic_state
|
||||||
#ifdef CONFIG_KVM_ARM_VGIC
|
|
||||||
/* Get VGIC VCTRL base into r2 */
|
/* Get VGIC VCTRL base into r2 */
|
||||||
ldr r2, [vcpu, #VCPU_KVM]
|
ldr r2, [vcpu, #VCPU_KVM]
|
||||||
ldr r2, [r2, #KVM_VGIC_VCTRL]
|
ldr r2, [r2, #KVM_VGIC_VCTRL]
|
||||||
@@ -501,7 +498,6 @@ ARM_BE8(rev r6, r6 )
|
|||||||
subs r4, r4, #1
|
subs r4, r4, #1
|
||||||
bne 1b
|
bne 1b
|
||||||
2:
|
2:
|
||||||
#endif
|
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
#define CNTHCTL_PL1PCTEN (1 << 0)
|
#define CNTHCTL_PL1PCTEN (1 << 0)
|
||||||
@@ -515,7 +511,6 @@ ARM_BE8(rev r6, r6 )
|
|||||||
* Clobbers r2-r5
|
* Clobbers r2-r5
|
||||||
*/
|
*/
|
||||||
.macro save_timer_state
|
.macro save_timer_state
|
||||||
#ifdef CONFIG_KVM_ARM_TIMER
|
|
||||||
ldr r4, [vcpu, #VCPU_KVM]
|
ldr r4, [vcpu, #VCPU_KVM]
|
||||||
ldr r2, [r4, #KVM_TIMER_ENABLED]
|
ldr r2, [r4, #KVM_TIMER_ENABLED]
|
||||||
cmp r2, #0
|
cmp r2, #0
|
||||||
@@ -537,7 +532,6 @@ ARM_BE8(rev r6, r6 )
|
|||||||
mcrr p15, 4, r2, r2, c14 @ CNTVOFF
|
mcrr p15, 4, r2, r2, c14 @ CNTVOFF
|
||||||
|
|
||||||
1:
|
1:
|
||||||
#endif
|
|
||||||
@ Allow physical timer/counter access for the host
|
@ Allow physical timer/counter access for the host
|
||||||
mrc p15, 4, r2, c14, c1, 0 @ CNTHCTL
|
mrc p15, 4, r2, c14, c1, 0 @ CNTHCTL
|
||||||
orr r2, r2, #(CNTHCTL_PL1PCEN | CNTHCTL_PL1PCTEN)
|
orr r2, r2, #(CNTHCTL_PL1PCEN | CNTHCTL_PL1PCTEN)
|
||||||
@@ -559,7 +553,6 @@ ARM_BE8(rev r6, r6 )
|
|||||||
bic r2, r2, #CNTHCTL_PL1PCEN
|
bic r2, r2, #CNTHCTL_PL1PCEN
|
||||||
mcr p15, 4, r2, c14, c1, 0 @ CNTHCTL
|
mcr p15, 4, r2, c14, c1, 0 @ CNTHCTL
|
||||||
|
|
||||||
#ifdef CONFIG_KVM_ARM_TIMER
|
|
||||||
ldr r4, [vcpu, #VCPU_KVM]
|
ldr r4, [vcpu, #VCPU_KVM]
|
||||||
ldr r2, [r4, #KVM_TIMER_ENABLED]
|
ldr r2, [r4, #KVM_TIMER_ENABLED]
|
||||||
cmp r2, #0
|
cmp r2, #0
|
||||||
@@ -579,7 +572,6 @@ ARM_BE8(rev r6, r6 )
|
|||||||
and r2, r2, #3
|
and r2, r2, #3
|
||||||
mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
|
mcr p15, 0, r2, c14, c3, 1 @ CNTV_CTL
|
||||||
1:
|
1:
|
||||||
#endif
|
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.equ vmentry, 0
|
.equ vmentry, 0
|
||||||
|
|||||||
+38
-28
@@ -121,12 +121,11 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
static int decode_hsr(struct kvm_vcpu *vcpu, bool *is_write, int *len)
|
||||||
struct kvm_exit_mmio *mmio)
|
|
||||||
{
|
{
|
||||||
unsigned long rt;
|
unsigned long rt;
|
||||||
int len;
|
int access_size;
|
||||||
bool is_write, sign_extend;
|
bool sign_extend;
|
||||||
|
|
||||||
if (kvm_vcpu_dabt_isextabt(vcpu)) {
|
if (kvm_vcpu_dabt_isextabt(vcpu)) {
|
||||||
/* cache operation on I/O addr, tell guest unsupported */
|
/* cache operation on I/O addr, tell guest unsupported */
|
||||||
@@ -140,17 +139,15 @@ static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = kvm_vcpu_dabt_get_as(vcpu);
|
access_size = kvm_vcpu_dabt_get_as(vcpu);
|
||||||
if (unlikely(len < 0))
|
if (unlikely(access_size < 0))
|
||||||
return len;
|
return access_size;
|
||||||
|
|
||||||
is_write = kvm_vcpu_dabt_iswrite(vcpu);
|
*is_write = kvm_vcpu_dabt_iswrite(vcpu);
|
||||||
sign_extend = kvm_vcpu_dabt_issext(vcpu);
|
sign_extend = kvm_vcpu_dabt_issext(vcpu);
|
||||||
rt = kvm_vcpu_dabt_get_rd(vcpu);
|
rt = kvm_vcpu_dabt_get_rd(vcpu);
|
||||||
|
|
||||||
mmio->is_write = is_write;
|
*len = access_size;
|
||||||
mmio->phys_addr = fault_ipa;
|
|
||||||
mmio->len = len;
|
|
||||||
vcpu->arch.mmio_decode.sign_extend = sign_extend;
|
vcpu->arch.mmio_decode.sign_extend = sign_extend;
|
||||||
vcpu->arch.mmio_decode.rt = rt;
|
vcpu->arch.mmio_decode.rt = rt;
|
||||||
|
|
||||||
@@ -165,20 +162,20 @@ static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
|||||||
int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
||||||
phys_addr_t fault_ipa)
|
phys_addr_t fault_ipa)
|
||||||
{
|
{
|
||||||
struct kvm_exit_mmio mmio;
|
|
||||||
unsigned long data;
|
unsigned long data;
|
||||||
unsigned long rt;
|
unsigned long rt;
|
||||||
int ret;
|
int ret;
|
||||||
|
bool is_write;
|
||||||
|
int len;
|
||||||
|
u8 data_buf[8];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepare MMIO operation. First stash it in a private
|
* Prepare MMIO operation. First decode the syndrome data we get
|
||||||
* structure that we can use for in-kernel emulation. If the
|
* from the CPU. Then try if some in-kernel emulation feels
|
||||||
* kernel can't handle it, copy it into run->mmio and let user
|
* responsible, otherwise let user space do its magic.
|
||||||
* space do its magic.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (kvm_vcpu_dabt_isvalid(vcpu)) {
|
if (kvm_vcpu_dabt_isvalid(vcpu)) {
|
||||||
ret = decode_hsr(vcpu, fault_ipa, &mmio);
|
ret = decode_hsr(vcpu, &is_write, &len);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
@@ -188,21 +185,34 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
|||||||
|
|
||||||
rt = vcpu->arch.mmio_decode.rt;
|
rt = vcpu->arch.mmio_decode.rt;
|
||||||
|
|
||||||
if (mmio.is_write) {
|
if (is_write) {
|
||||||
data = vcpu_data_guest_to_host(vcpu, *vcpu_reg(vcpu, rt),
|
data = vcpu_data_guest_to_host(vcpu, *vcpu_reg(vcpu, rt), len);
|
||||||
mmio.len);
|
|
||||||
|
|
||||||
trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, mmio.len,
|
trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data);
|
||||||
fault_ipa, data);
|
mmio_write_buf(data_buf, len, data);
|
||||||
mmio_write_buf(mmio.data, mmio.len, data);
|
|
||||||
|
ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len,
|
||||||
|
data_buf);
|
||||||
} else {
|
} else {
|
||||||
trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, mmio.len,
|
trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, len,
|
||||||
fault_ipa, 0);
|
fault_ipa, 0);
|
||||||
|
|
||||||
|
ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_ipa, len,
|
||||||
|
data_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vgic_handle_mmio(vcpu, run, &mmio))
|
/* Now prepare kvm_run for the potential return to userland. */
|
||||||
return 1;
|
run->mmio.is_write = is_write;
|
||||||
|
run->mmio.phys_addr = fault_ipa;
|
||||||
|
run->mmio.len = len;
|
||||||
|
memcpy(run->mmio.data, data_buf, len);
|
||||||
|
|
||||||
kvm_prepare_mmio(run, &mmio);
|
if (!ret) {
|
||||||
|
/* We handled the access successfully in the kernel. */
|
||||||
|
kvm_handle_mmio_return(vcpu, run);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
run->exit_reason = KVM_EXIT_MMIO;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+124
-10
@@ -1330,10 +1330,51 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
|||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
spin_unlock(&kvm->mmu_lock);
|
spin_unlock(&kvm->mmu_lock);
|
||||||
|
kvm_set_pfn_accessed(pfn);
|
||||||
kvm_release_pfn_clean(pfn);
|
kvm_release_pfn_clean(pfn);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resolve the access fault by making the page young again.
|
||||||
|
* Note that because the faulting entry is guaranteed not to be
|
||||||
|
* cached in the TLB, we don't need to invalidate anything.
|
||||||
|
*/
|
||||||
|
static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
|
||||||
|
{
|
||||||
|
pmd_t *pmd;
|
||||||
|
pte_t *pte;
|
||||||
|
pfn_t pfn;
|
||||||
|
bool pfn_valid = false;
|
||||||
|
|
||||||
|
trace_kvm_access_fault(fault_ipa);
|
||||||
|
|
||||||
|
spin_lock(&vcpu->kvm->mmu_lock);
|
||||||
|
|
||||||
|
pmd = stage2_get_pmd(vcpu->kvm, NULL, fault_ipa);
|
||||||
|
if (!pmd || pmd_none(*pmd)) /* Nothing there */
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (kvm_pmd_huge(*pmd)) { /* THP, HugeTLB */
|
||||||
|
*pmd = pmd_mkyoung(*pmd);
|
||||||
|
pfn = pmd_pfn(*pmd);
|
||||||
|
pfn_valid = true;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
pte = pte_offset_kernel(pmd, fault_ipa);
|
||||||
|
if (pte_none(*pte)) /* Nothing there either */
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
*pte = pte_mkyoung(*pte); /* Just a page... */
|
||||||
|
pfn = pte_pfn(*pte);
|
||||||
|
pfn_valid = true;
|
||||||
|
out:
|
||||||
|
spin_unlock(&vcpu->kvm->mmu_lock);
|
||||||
|
if (pfn_valid)
|
||||||
|
kvm_set_pfn_accessed(pfn);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kvm_handle_guest_abort - handles all 2nd stage aborts
|
* kvm_handle_guest_abort - handles all 2nd stage aborts
|
||||||
* @vcpu: the VCPU pointer
|
* @vcpu: the VCPU pointer
|
||||||
@@ -1364,7 +1405,8 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||||||
|
|
||||||
/* Check the stage-2 fault is trans. fault or write fault */
|
/* Check the stage-2 fault is trans. fault or write fault */
|
||||||
fault_status = kvm_vcpu_trap_get_fault_type(vcpu);
|
fault_status = kvm_vcpu_trap_get_fault_type(vcpu);
|
||||||
if (fault_status != FSC_FAULT && fault_status != FSC_PERM) {
|
if (fault_status != FSC_FAULT && fault_status != FSC_PERM &&
|
||||||
|
fault_status != FSC_ACCESS) {
|
||||||
kvm_err("Unsupported FSC: EC=%#x xFSC=%#lx ESR_EL2=%#lx\n",
|
kvm_err("Unsupported FSC: EC=%#x xFSC=%#lx ESR_EL2=%#lx\n",
|
||||||
kvm_vcpu_trap_get_class(vcpu),
|
kvm_vcpu_trap_get_class(vcpu),
|
||||||
(unsigned long)kvm_vcpu_trap_get_fault(vcpu),
|
(unsigned long)kvm_vcpu_trap_get_fault(vcpu),
|
||||||
@@ -1400,6 +1442,12 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
|||||||
/* Userspace should not be able to register out-of-bounds IPAs */
|
/* Userspace should not be able to register out-of-bounds IPAs */
|
||||||
VM_BUG_ON(fault_ipa >= KVM_PHYS_SIZE);
|
VM_BUG_ON(fault_ipa >= KVM_PHYS_SIZE);
|
||||||
|
|
||||||
|
if (fault_status == FSC_ACCESS) {
|
||||||
|
handle_access_fault(vcpu, fault_ipa);
|
||||||
|
ret = 1;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
ret = user_mem_abort(vcpu, fault_ipa, memslot, hva, fault_status);
|
ret = user_mem_abort(vcpu, fault_ipa, memslot, hva, fault_status);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
@@ -1408,15 +1456,16 @@ out_unlock:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_hva_to_gpa(struct kvm *kvm,
|
static int handle_hva_to_gpa(struct kvm *kvm,
|
||||||
unsigned long start,
|
unsigned long start,
|
||||||
unsigned long end,
|
unsigned long end,
|
||||||
void (*handler)(struct kvm *kvm,
|
int (*handler)(struct kvm *kvm,
|
||||||
gpa_t gpa, void *data),
|
gpa_t gpa, void *data),
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
struct kvm_memslots *slots;
|
struct kvm_memslots *slots;
|
||||||
struct kvm_memory_slot *memslot;
|
struct kvm_memory_slot *memslot;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
slots = kvm_memslots(kvm);
|
slots = kvm_memslots(kvm);
|
||||||
|
|
||||||
@@ -1440,14 +1489,17 @@ static void handle_hva_to_gpa(struct kvm *kvm,
|
|||||||
|
|
||||||
for (; gfn < gfn_end; ++gfn) {
|
for (; gfn < gfn_end; ++gfn) {
|
||||||
gpa_t gpa = gfn << PAGE_SHIFT;
|
gpa_t gpa = gfn << PAGE_SHIFT;
|
||||||
handler(kvm, gpa, data);
|
ret |= handler(kvm, gpa, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvm_unmap_hva_handler(struct kvm *kvm, gpa_t gpa, void *data)
|
static int kvm_unmap_hva_handler(struct kvm *kvm, gpa_t gpa, void *data)
|
||||||
{
|
{
|
||||||
unmap_stage2_range(kvm, gpa, PAGE_SIZE);
|
unmap_stage2_range(kvm, gpa, PAGE_SIZE);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
|
int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
|
||||||
@@ -1473,7 +1525,7 @@ int kvm_unmap_hva_range(struct kvm *kvm,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvm_set_spte_handler(struct kvm *kvm, gpa_t gpa, void *data)
|
static int kvm_set_spte_handler(struct kvm *kvm, gpa_t gpa, void *data)
|
||||||
{
|
{
|
||||||
pte_t *pte = (pte_t *)data;
|
pte_t *pte = (pte_t *)data;
|
||||||
|
|
||||||
@@ -1485,6 +1537,7 @@ static void kvm_set_spte_handler(struct kvm *kvm, gpa_t gpa, void *data)
|
|||||||
* through this calling path.
|
* through this calling path.
|
||||||
*/
|
*/
|
||||||
stage2_set_pte(kvm, NULL, gpa, pte, 0);
|
stage2_set_pte(kvm, NULL, gpa, pte, 0);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1501,6 +1554,67 @@ void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
|
|||||||
handle_hva_to_gpa(kvm, hva, end, &kvm_set_spte_handler, &stage2_pte);
|
handle_hva_to_gpa(kvm, hva, end, &kvm_set_spte_handler, &stage2_pte);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int kvm_age_hva_handler(struct kvm *kvm, gpa_t gpa, void *data)
|
||||||
|
{
|
||||||
|
pmd_t *pmd;
|
||||||
|
pte_t *pte;
|
||||||
|
|
||||||
|
pmd = stage2_get_pmd(kvm, NULL, gpa);
|
||||||
|
if (!pmd || pmd_none(*pmd)) /* Nothing there */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (kvm_pmd_huge(*pmd)) { /* THP, HugeTLB */
|
||||||
|
if (pmd_young(*pmd)) {
|
||||||
|
*pmd = pmd_mkold(*pmd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pte = pte_offset_kernel(pmd, gpa);
|
||||||
|
if (pte_none(*pte))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (pte_young(*pte)) {
|
||||||
|
*pte = pte_mkold(*pte); /* Just a page... */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvm_test_age_hva_handler(struct kvm *kvm, gpa_t gpa, void *data)
|
||||||
|
{
|
||||||
|
pmd_t *pmd;
|
||||||
|
pte_t *pte;
|
||||||
|
|
||||||
|
pmd = stage2_get_pmd(kvm, NULL, gpa);
|
||||||
|
if (!pmd || pmd_none(*pmd)) /* Nothing there */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (kvm_pmd_huge(*pmd)) /* THP, HugeTLB */
|
||||||
|
return pmd_young(*pmd);
|
||||||
|
|
||||||
|
pte = pte_offset_kernel(pmd, gpa);
|
||||||
|
if (!pte_none(*pte)) /* Just a page... */
|
||||||
|
return pte_young(*pte);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end)
|
||||||
|
{
|
||||||
|
trace_kvm_age_hva(start, end);
|
||||||
|
return handle_hva_to_gpa(kvm, start, end, kvm_age_hva_handler, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
|
||||||
|
{
|
||||||
|
trace_kvm_test_age_hva(hva);
|
||||||
|
return handle_hva_to_gpa(kvm, hva, hva, kvm_test_age_hva_handler, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu)
|
void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
mmu_free_memory_cache(&vcpu->arch.mmu_page_cache);
|
mmu_free_memory_cache(&vcpu->arch.mmu_page_cache);
|
||||||
|
|||||||
@@ -68,6 +68,21 @@ TRACE_EVENT(kvm_guest_fault,
|
|||||||
__entry->hxfar, __entry->vcpu_pc)
|
__entry->hxfar, __entry->vcpu_pc)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(kvm_access_fault,
|
||||||
|
TP_PROTO(unsigned long ipa),
|
||||||
|
TP_ARGS(ipa),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field( unsigned long, ipa )
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->ipa = ipa;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("IPA: %lx", __entry->ipa)
|
||||||
|
);
|
||||||
|
|
||||||
TRACE_EVENT(kvm_irq_line,
|
TRACE_EVENT(kvm_irq_line,
|
||||||
TP_PROTO(unsigned int type, int vcpu_idx, int irq_num, int level),
|
TP_PROTO(unsigned int type, int vcpu_idx, int irq_num, int level),
|
||||||
TP_ARGS(type, vcpu_idx, irq_num, level),
|
TP_ARGS(type, vcpu_idx, irq_num, level),
|
||||||
@@ -210,6 +225,39 @@ TRACE_EVENT(kvm_set_spte_hva,
|
|||||||
TP_printk("mmu notifier set pte hva: %#08lx", __entry->hva)
|
TP_printk("mmu notifier set pte hva: %#08lx", __entry->hva)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(kvm_age_hva,
|
||||||
|
TP_PROTO(unsigned long start, unsigned long end),
|
||||||
|
TP_ARGS(start, end),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field( unsigned long, start )
|
||||||
|
__field( unsigned long, end )
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->start = start;
|
||||||
|
__entry->end = end;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("mmu notifier age hva: %#08lx -- %#08lx",
|
||||||
|
__entry->start, __entry->end)
|
||||||
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(kvm_test_age_hva,
|
||||||
|
TP_PROTO(unsigned long hva),
|
||||||
|
TP_ARGS(hva),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field( unsigned long, hva )
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->hva = hva;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("mmu notifier test age hva: %#08lx", __entry->hva)
|
||||||
|
);
|
||||||
|
|
||||||
TRACE_EVENT(kvm_hvc,
|
TRACE_EVENT(kvm_hvc,
|
||||||
TP_PROTO(unsigned long vcpu_pc, unsigned long r0, unsigned long imm),
|
TP_PROTO(unsigned long vcpu_pc, unsigned long r0, unsigned long imm),
|
||||||
TP_ARGS(vcpu_pc, r0, imm),
|
TP_ARGS(vcpu_pc, r0, imm),
|
||||||
|
|||||||
@@ -90,6 +90,7 @@
|
|||||||
#define ESR_ELx_FSC (0x3F)
|
#define ESR_ELx_FSC (0x3F)
|
||||||
#define ESR_ELx_FSC_TYPE (0x3C)
|
#define ESR_ELx_FSC_TYPE (0x3C)
|
||||||
#define ESR_ELx_FSC_EXTABT (0x10)
|
#define ESR_ELx_FSC_EXTABT (0x10)
|
||||||
|
#define ESR_ELx_FSC_ACCESS (0x08)
|
||||||
#define ESR_ELx_FSC_FAULT (0x04)
|
#define ESR_ELx_FSC_FAULT (0x04)
|
||||||
#define ESR_ELx_FSC_PERM (0x0C)
|
#define ESR_ELx_FSC_PERM (0x0C)
|
||||||
#define ESR_ELx_CV (UL(1) << 24)
|
#define ESR_ELx_CV (UL(1) << 24)
|
||||||
|
|||||||
@@ -188,6 +188,7 @@
|
|||||||
|
|
||||||
/* For compatibility with fault code shared with 32-bit */
|
/* For compatibility with fault code shared with 32-bit */
|
||||||
#define FSC_FAULT ESR_ELx_FSC_FAULT
|
#define FSC_FAULT ESR_ELx_FSC_FAULT
|
||||||
|
#define FSC_ACCESS ESR_ELx_FSC_ACCESS
|
||||||
#define FSC_PERM ESR_ELx_FSC_PERM
|
#define FSC_PERM ESR_ELx_FSC_PERM
|
||||||
|
|
||||||
/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
|
/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
#include <asm/kvm_asm.h>
|
#include <asm/kvm_asm.h>
|
||||||
#include <asm/kvm_mmio.h>
|
#include <asm/kvm_mmio.h>
|
||||||
|
|
||||||
|
#define __KVM_HAVE_ARCH_INTC_INITIALIZED
|
||||||
|
|
||||||
#if defined(CONFIG_KVM_ARM_MAX_VCPUS)
|
#if defined(CONFIG_KVM_ARM_MAX_VCPUS)
|
||||||
#define KVM_MAX_VCPUS CONFIG_KVM_ARM_MAX_VCPUS
|
#define KVM_MAX_VCPUS CONFIG_KVM_ARM_MAX_VCPUS
|
||||||
#else
|
#else
|
||||||
@@ -177,19 +179,10 @@ int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
|
|||||||
int kvm_unmap_hva_range(struct kvm *kvm,
|
int kvm_unmap_hva_range(struct kvm *kvm,
|
||||||
unsigned long start, unsigned long end);
|
unsigned long start, unsigned long end);
|
||||||
void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
|
void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
|
||||||
|
int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
|
||||||
|
int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
|
||||||
|
|
||||||
/* We do not have shadow page tables, hence the empty hooks */
|
/* We do not have shadow page tables, hence the empty hooks */
|
||||||
static inline int kvm_age_hva(struct kvm *kvm, unsigned long start,
|
|
||||||
unsigned long end)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
|
static inline void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
|
||||||
unsigned long address)
|
unsigned long address)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,28 +31,6 @@ struct kvm_decode {
|
|||||||
bool sign_extend;
|
bool sign_extend;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* The in-kernel MMIO emulation code wants to use a copy of run->mmio,
|
|
||||||
* which is an anonymous type. Use our own type instead.
|
|
||||||
*/
|
|
||||||
struct kvm_exit_mmio {
|
|
||||||
phys_addr_t phys_addr;
|
|
||||||
u8 data[8];
|
|
||||||
u32 len;
|
|
||||||
bool is_write;
|
|
||||||
void *private;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline void kvm_prepare_mmio(struct kvm_run *run,
|
|
||||||
struct kvm_exit_mmio *mmio)
|
|
||||||
{
|
|
||||||
run->mmio.phys_addr = mmio->phys_addr;
|
|
||||||
run->mmio.len = mmio->len;
|
|
||||||
run->mmio.is_write = mmio->is_write;
|
|
||||||
memcpy(run->mmio.data, mmio->data, mmio->len);
|
|
||||||
run->exit_reason = KVM_EXIT_MMIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||||
int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
|
||||||
phys_addr_t fault_ipa);
|
phys_addr_t fault_ipa);
|
||||||
|
|||||||
@@ -191,6 +191,9 @@ struct kvm_arch_memory_slot {
|
|||||||
/* Highest supported SPI, from VGIC_NR_IRQS */
|
/* Highest supported SPI, from VGIC_NR_IRQS */
|
||||||
#define KVM_ARM_IRQ_GIC_MAX 127
|
#define KVM_ARM_IRQ_GIC_MAX 127
|
||||||
|
|
||||||
|
/* One single KVM irqchip, ie. the VGIC */
|
||||||
|
#define KVM_NR_IRQCHIPS 1
|
||||||
|
|
||||||
/* PSCI interface */
|
/* PSCI interface */
|
||||||
#define KVM_PSCI_FN_BASE 0x95c1ba5e
|
#define KVM_PSCI_FN_BASE 0x95c1ba5e
|
||||||
#define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n))
|
#define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n))
|
||||||
|
|||||||
+3
-15
@@ -18,6 +18,7 @@ if VIRTUALIZATION
|
|||||||
|
|
||||||
config KVM
|
config KVM
|
||||||
bool "Kernel-based Virtual Machine (KVM) support"
|
bool "Kernel-based Virtual Machine (KVM) support"
|
||||||
|
depends on OF
|
||||||
select MMU_NOTIFIER
|
select MMU_NOTIFIER
|
||||||
select PREEMPT_NOTIFIERS
|
select PREEMPT_NOTIFIERS
|
||||||
select ANON_INODES
|
select ANON_INODES
|
||||||
@@ -25,10 +26,10 @@ config KVM
|
|||||||
select HAVE_KVM_ARCH_TLB_FLUSH_ALL
|
select HAVE_KVM_ARCH_TLB_FLUSH_ALL
|
||||||
select KVM_MMIO
|
select KVM_MMIO
|
||||||
select KVM_ARM_HOST
|
select KVM_ARM_HOST
|
||||||
select KVM_ARM_VGIC
|
|
||||||
select KVM_ARM_TIMER
|
|
||||||
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
|
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
|
||||||
select SRCU
|
select SRCU
|
||||||
|
select HAVE_KVM_EVENTFD
|
||||||
|
select HAVE_KVM_IRQFD
|
||||||
---help---
|
---help---
|
||||||
Support hosting virtualized guest machines.
|
Support hosting virtualized guest machines.
|
||||||
|
|
||||||
@@ -50,17 +51,4 @@ config KVM_ARM_MAX_VCPUS
|
|||||||
large, so only choose a reasonable number that you expect to
|
large, so only choose a reasonable number that you expect to
|
||||||
actually use.
|
actually use.
|
||||||
|
|
||||||
config KVM_ARM_VGIC
|
|
||||||
bool
|
|
||||||
depends on KVM_ARM_HOST && OF
|
|
||||||
select HAVE_KVM_IRQCHIP
|
|
||||||
---help---
|
|
||||||
Adds support for a hardware assisted, in-kernel GIC emulation.
|
|
||||||
|
|
||||||
config KVM_ARM_TIMER
|
|
||||||
bool
|
|
||||||
depends on KVM_ARM_VGIC
|
|
||||||
---help---
|
|
||||||
Adds support for the Architected Timers in virtual machines.
|
|
||||||
|
|
||||||
endif # VIRTUALIZATION
|
endif # VIRTUALIZATION
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user