Commit e28e909c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm

Pull second batch of KVM updates from Radim Krčmář:
 "General:

   - move kvm_stat tool from QEMU repo into tools/kvm/kvm_stat (kvm_stat
     had nothing to do with QEMU in the first place -- the tool only
     interprets debugfs)

   - expose per-vm statistics in debugfs and support them in kvm_stat
     (KVM always collected per-vm statistics, but they were summarised
     into global statistics)

  x86:

   - fix dynamic APICv (VMX was improperly configured and a guest could
     access host's APIC MSRs, CVE-2016-4440)

   - minor fixes

  ARM changes from Christoffer Dall:

   - new vgic reimplementation of our horribly broken legacy vgic
     implementation.  The two implementations will live side-by-side
     (with the new being the configured default) for one kernel release
     and then we'll remove the legacy one.

   - fix for a non-critical issue with virtual abort injection to guests"

* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (70 commits)
  tools: kvm_stat: Add comments
  tools: kvm_stat: Introduce pid monitoring
  KVM: Create debugfs dir and stat files for each VM
  MAINTAINERS: Add kvm tools
  tools: kvm_stat: Powerpc related fixes
  tools: Add kvm_stat man page
  tools: Add kvm_stat vm monitor script
  kvm:vmx: more complete state update on APICv on/off
  KVM: SVM: Add more SVM_EXIT_REASONS
  KVM: Unify traced vector format
  svm: bitwise vs logical op typo
  KVM: arm/arm64: vgic-new: Synchronize changes to active state
  KVM: arm/arm64: vgic-new: enable build
  KVM: arm/arm64: vgic-new: implement mapped IRQ handling
  KVM: arm/arm64: vgic-new: Wire up irqfd injection
  KVM: arm/arm64: vgic-new: Add vgic_v2/v3_enable
  KVM: arm/arm64: vgic-new: vgic_init: implement map_resources
  KVM: arm/arm64: vgic-new: vgic_init: implement vgic_init
  KVM: arm/arm64: vgic-new: vgic_init: implement vgic_create
  KVM: arm/arm64: vgic-new: vgic_init: implement kvm_vgic_hyp_init
  ...
parents dc03c0f9 fabc7128
...@@ -6491,6 +6491,7 @@ F: arch/*/include/asm/kvm* ...@@ -6491,6 +6491,7 @@ F: arch/*/include/asm/kvm*
F: include/linux/kvm* F: include/linux/kvm*
F: include/uapi/linux/kvm* F: include/uapi/linux/kvm*
F: virt/kvm/ F: virt/kvm/
F: tools/kvm/
KERNEL VIRTUAL MACHINE (KVM) FOR AMD-V KERNEL VIRTUAL MACHINE (KVM) FOR AMD-V
M: Joerg Roedel <joro@8bytes.org> M: Joerg Roedel <joro@8bytes.org>
......
...@@ -41,6 +41,8 @@ ...@@ -41,6 +41,8 @@
#define KVM_MAX_VCPUS VGIC_V2_MAX_CPUS #define KVM_MAX_VCPUS VGIC_V2_MAX_CPUS
#define KVM_REQ_VCPU_EXIT 8
u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode); u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
int __attribute_const__ kvm_target_cpu(void); int __attribute_const__ kvm_target_cpu(void);
int kvm_reset_vcpu(struct kvm_vcpu *vcpu); int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
...@@ -226,6 +228,10 @@ static inline void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm, ...@@ -226,6 +228,10 @@ static inline void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
struct kvm_vcpu *kvm_arm_get_running_vcpu(void); struct kvm_vcpu *kvm_arm_get_running_vcpu(void);
struct kvm_vcpu __percpu **kvm_get_running_vcpus(void); struct kvm_vcpu __percpu **kvm_get_running_vcpus(void);
void kvm_arm_halt_guest(struct kvm *kvm);
void kvm_arm_resume_guest(struct kvm *kvm);
void kvm_arm_halt_vcpu(struct kvm_vcpu *vcpu);
void kvm_arm_resume_vcpu(struct kvm_vcpu *vcpu);
int kvm_arm_copy_coproc_indices(struct kvm_vcpu *vcpu, u64 __user *uindices); int kvm_arm_copy_coproc_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
unsigned long kvm_arm_num_coproc_regs(struct kvm_vcpu *vcpu); unsigned long kvm_arm_num_coproc_regs(struct kvm_vcpu *vcpu);
......
...@@ -28,6 +28,9 @@ struct kvm_decode { ...@@ -28,6 +28,9 @@ struct kvm_decode {
bool sign_extend; bool sign_extend;
}; };
void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
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);
......
...@@ -46,6 +46,13 @@ config KVM_ARM_HOST ...@@ -46,6 +46,13 @@ config KVM_ARM_HOST
---help--- ---help---
Provides host support for ARM processors. Provides host support for ARM processors.
config KVM_NEW_VGIC
bool "New VGIC implementation"
depends on KVM
default y
---help---
uses the new VGIC implementation
source drivers/vhost/Kconfig source drivers/vhost/Kconfig
endif # VIRTUALIZATION endif # VIRTUALIZATION
...@@ -21,7 +21,18 @@ obj-$(CONFIG_KVM_ARM_HOST) += hyp/ ...@@ -21,7 +21,18 @@ obj-$(CONFIG_KVM_ARM_HOST) += hyp/
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
ifeq ($(CONFIG_KVM_NEW_VGIC),y)
obj-y += $(KVM)/arm/vgic/vgic.o
obj-y += $(KVM)/arm/vgic/vgic-init.o
obj-y += $(KVM)/arm/vgic/vgic-irqfd.o
obj-y += $(KVM)/arm/vgic/vgic-v2.o
obj-y += $(KVM)/arm/vgic/vgic-mmio.o
obj-y += $(KVM)/arm/vgic/vgic-mmio-v2.o
obj-y += $(KVM)/arm/vgic/vgic-kvm-device.o
else
obj-y += $(KVM)/arm/vgic.o obj-y += $(KVM)/arm/vgic.o
obj-y += $(KVM)/arm/vgic-v2.o obj-y += $(KVM)/arm/vgic-v2.o
obj-y += $(KVM)/arm/vgic-v2-emul.o obj-y += $(KVM)/arm/vgic-v2-emul.o
endif
obj-y += $(KVM)/arm/arch_timer.o obj-y += $(KVM)/arm/arch_timer.o
...@@ -455,7 +455,7 @@ static void update_vttbr(struct kvm *kvm) ...@@ -455,7 +455,7 @@ static void update_vttbr(struct kvm *kvm)
static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu) static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
{ {
struct kvm *kvm = vcpu->kvm; struct kvm *kvm = vcpu->kvm;
int ret; int ret = 0;
if (likely(vcpu->arch.has_run_once)) if (likely(vcpu->arch.has_run_once))
return 0; return 0;
...@@ -478,9 +478,9 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu) ...@@ -478,9 +478,9 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu)
* interrupts from the virtual timer with a userspace gic. * interrupts from the virtual timer with a userspace gic.
*/ */
if (irqchip_in_kernel(kvm) && vgic_initialized(kvm)) if (irqchip_in_kernel(kvm) && vgic_initialized(kvm))
kvm_timer_enable(kvm); ret = kvm_timer_enable(vcpu);
return 0; return ret;
} }
bool kvm_arch_intc_initialized(struct kvm *kvm) bool kvm_arch_intc_initialized(struct kvm *kvm)
...@@ -488,30 +488,37 @@ bool kvm_arch_intc_initialized(struct kvm *kvm) ...@@ -488,30 +488,37 @@ bool kvm_arch_intc_initialized(struct kvm *kvm)
return vgic_initialized(kvm); return vgic_initialized(kvm);
} }
static void kvm_arm_halt_guest(struct kvm *kvm) __maybe_unused; void kvm_arm_halt_guest(struct kvm *kvm)
static void kvm_arm_resume_guest(struct kvm *kvm) __maybe_unused;
static void kvm_arm_halt_guest(struct kvm *kvm)
{ {
int i; int i;
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu;
kvm_for_each_vcpu(i, vcpu, kvm) kvm_for_each_vcpu(i, vcpu, kvm)
vcpu->arch.pause = true; vcpu->arch.pause = true;
force_vm_exit(cpu_all_mask); kvm_make_all_cpus_request(kvm, KVM_REQ_VCPU_EXIT);
} }
static void kvm_arm_resume_guest(struct kvm *kvm) void kvm_arm_halt_vcpu(struct kvm_vcpu *vcpu)
{ {
int i; vcpu->arch.pause = true;
struct kvm_vcpu *vcpu; kvm_vcpu_kick(vcpu);
}
kvm_for_each_vcpu(i, vcpu, kvm) { void kvm_arm_resume_vcpu(struct kvm_vcpu *vcpu)
{
struct swait_queue_head *wq = kvm_arch_vcpu_wq(vcpu); struct swait_queue_head *wq = kvm_arch_vcpu_wq(vcpu);
vcpu->arch.pause = false; vcpu->arch.pause = false;
swake_up(wq); swake_up(wq);
} }
void kvm_arm_resume_guest(struct kvm *kvm)
{
int i;
struct kvm_vcpu *vcpu;
kvm_for_each_vcpu(i, vcpu, kvm)
kvm_arm_resume_vcpu(vcpu);
} }
static void vcpu_sleep(struct kvm_vcpu *vcpu) static void vcpu_sleep(struct kvm_vcpu *vcpu)
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "trace.h" #include "trace.h"
static void mmio_write_buf(char *buf, unsigned int len, unsigned long data) void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data)
{ {
void *datap = NULL; void *datap = NULL;
union { union {
...@@ -55,7 +55,7 @@ static void mmio_write_buf(char *buf, unsigned int len, unsigned long data) ...@@ -55,7 +55,7 @@ static void mmio_write_buf(char *buf, unsigned int len, unsigned long data)
memcpy(buf, datap, len); memcpy(buf, datap, len);
} }
static unsigned long mmio_read_buf(char *buf, unsigned int len) unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len)
{ {
unsigned long data = 0; unsigned long data = 0;
union { union {
...@@ -66,7 +66,7 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len) ...@@ -66,7 +66,7 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len)
switch (len) { switch (len) {
case 1: case 1:
data = buf[0]; data = *(u8 *)buf;
break; break;
case 2: case 2:
memcpy(&tmp.hword, buf, len); memcpy(&tmp.hword, buf, len);
...@@ -87,11 +87,10 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len) ...@@ -87,11 +87,10 @@ static unsigned long mmio_read_buf(char *buf, unsigned int len)
/** /**
* kvm_handle_mmio_return -- Handle MMIO loads after user space emulation * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
* or in-kernel IO emulation
*
* @vcpu: The VCPU pointer * @vcpu: The VCPU pointer
* @run: The VCPU run struct containing the mmio data * @run: The VCPU run struct containing the mmio data
*
* This should only be called after returning from userspace for MMIO load
* emulation.
*/ */
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)
{ {
...@@ -104,7 +103,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) ...@@ -104,7 +103,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
if (len > sizeof(unsigned long)) if (len > sizeof(unsigned long))
return -EINVAL; return -EINVAL;
data = mmio_read_buf(run->mmio.data, len); data = kvm_mmio_read_buf(run->mmio.data, len);
if (vcpu->arch.mmio_decode.sign_extend && if (vcpu->arch.mmio_decode.sign_extend &&
len < sizeof(unsigned long)) { len < sizeof(unsigned long)) {
...@@ -190,7 +189,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, ...@@ -190,7 +189,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
len); len);
trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data); trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data);
mmio_write_buf(data_buf, len, data); kvm_mmio_write_buf(data_buf, len, data);
ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len, ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len,
data_buf); data_buf);
...@@ -206,18 +205,19 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, ...@@ -206,18 +205,19 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
run->mmio.is_write = is_write; run->mmio.is_write = is_write;
run->mmio.phys_addr = fault_ipa; run->mmio.phys_addr = fault_ipa;
run->mmio.len = len; run->mmio.len = len;
if (is_write)
memcpy(run->mmio.data, data_buf, len);
if (!ret) { if (!ret) {
/* We handled the access successfully in the kernel. */ /* We handled the access successfully in the kernel. */
if (!is_write)
memcpy(run->mmio.data, data_buf, len);
vcpu->stat.mmio_exit_kernel++; vcpu->stat.mmio_exit_kernel++;
kvm_handle_mmio_return(vcpu, run); kvm_handle_mmio_return(vcpu, run);
return 1; return 1;
} else {
vcpu->stat.mmio_exit_user++;
} }
if (is_write)
memcpy(run->mmio.data, data_buf, len);
vcpu->stat.mmio_exit_user++;
run->exit_reason = KVM_EXIT_MMIO; run->exit_reason = KVM_EXIT_MMIO;
return 0; return 0;
} }
...@@ -43,6 +43,8 @@ ...@@ -43,6 +43,8 @@
#define KVM_VCPU_MAX_FEATURES 4 #define KVM_VCPU_MAX_FEATURES 4
#define KVM_REQ_VCPU_EXIT 8
int __attribute_const__ kvm_target_cpu(void); int __attribute_const__ kvm_target_cpu(void);
int kvm_reset_vcpu(struct kvm_vcpu *vcpu); int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
int kvm_arch_dev_ioctl_check_extension(long ext); int kvm_arch_dev_ioctl_check_extension(long ext);
...@@ -327,6 +329,10 @@ static inline void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm, ...@@ -327,6 +329,10 @@ static inline void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
struct kvm_vcpu *kvm_arm_get_running_vcpu(void); struct kvm_vcpu *kvm_arm_get_running_vcpu(void);
struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void); struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void);
void kvm_arm_halt_guest(struct kvm *kvm);
void kvm_arm_resume_guest(struct kvm *kvm);
void kvm_arm_halt_vcpu(struct kvm_vcpu *vcpu);
void kvm_arm_resume_vcpu(struct kvm_vcpu *vcpu);
u64 __kvm_call_hyp(void *hypfn, ...); u64 __kvm_call_hyp(void *hypfn, ...);
#define kvm_call_hyp(f, ...) __kvm_call_hyp(kvm_ksym_ref(f), ##__VA_ARGS__) #define kvm_call_hyp(f, ...) __kvm_call_hyp(kvm_ksym_ref(f), ##__VA_ARGS__)
......
...@@ -30,6 +30,9 @@ struct kvm_decode { ...@@ -30,6 +30,9 @@ struct kvm_decode {
bool sign_extend; bool sign_extend;
}; };
void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
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);
......
...@@ -54,6 +54,13 @@ config KVM_ARM_PMU ...@@ -54,6 +54,13 @@ config KVM_ARM_PMU
Adds support for a virtual Performance Monitoring Unit (PMU) in Adds support for a virtual Performance Monitoring Unit (PMU) in
virtual machines. virtual machines.
config KVM_NEW_VGIC
bool "New VGIC implementation"
depends on KVM
default y
---help---
uses the new VGIC implementation
source drivers/vhost/Kconfig source drivers/vhost/Kconfig
endif # VIRTUALIZATION endif # VIRTUALIZATION
...@@ -20,10 +20,22 @@ kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o ...@@ -20,10 +20,22 @@ kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o
kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.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) += guest.o debug.o reset.o sys_regs.o sys_regs_generic_v8.o
ifeq ($(CONFIG_KVM_NEW_VGIC),y)
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-init.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-irqfd.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v2.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-v3.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v2.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o
else
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
endif
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
...@@ -162,7 +162,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr ...@@ -162,7 +162,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
esr |= (ESR_ELx_EC_IABT_CUR << ESR_ELx_EC_SHIFT); esr |= (ESR_ELx_EC_IABT_CUR << ESR_ELx_EC_SHIFT);
if (!is_iabt) if (!is_iabt)
esr |= ESR_ELx_EC_DABT_LOW; esr |= ESR_ELx_EC_DABT_LOW << ESR_ELx_EC_SHIFT;
vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_ELx_FSC_EXTABT; vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_ELx_FSC_EXTABT;
} }
......
...@@ -2,10 +2,12 @@ ...@@ -2,10 +2,12 @@
#define _UAPI__SVM_H #define _UAPI__SVM_H
#define SVM_EXIT_READ_CR0 0x000 #define SVM_EXIT_READ_CR0 0x000
#define SVM_EXIT_READ_CR2 0x002
#define SVM_EXIT_READ_CR3 0x003 #define SVM_EXIT_READ_CR3 0x003
#define SVM_EXIT_READ_CR4 0x004 #define SVM_EXIT_READ_CR4 0x004
#define SVM_EXIT_READ_CR8 0x008 #define SVM_EXIT_READ_CR8 0x008
#define SVM_EXIT_WRITE_CR0 0x010 #define SVM_EXIT_WRITE_CR0 0x010
#define SVM_EXIT_WRITE_CR2 0x012
#define SVM_EXIT_WRITE_CR3 0x013 #define SVM_EXIT_WRITE_CR3 0x013
#define SVM_EXIT_WRITE_CR4 0x014 #define SVM_EXIT_WRITE_CR4 0x014
#define SVM_EXIT_WRITE_CR8 0x018 #define SVM_EXIT_WRITE_CR8 0x018
...@@ -80,10 +82,12 @@ ...@@ -80,10 +82,12 @@
#define SVM_EXIT_REASONS \ #define SVM_EXIT_REASONS \
{ SVM_EXIT_READ_CR0, "read_cr0" }, \ { SVM_EXIT_READ_CR0, "read_cr0" }, \
{ SVM_EXIT_READ_CR2, "read_cr2" }, \
{ SVM_EXIT_READ_CR3, "read_cr3" }, \ { SVM_EXIT_READ_CR3, "read_cr3" }, \
{ SVM_EXIT_READ_CR4, "read_cr4" }, \ { SVM_EXIT_READ_CR4, "read_cr4" }, \
{ SVM_EXIT_READ_CR8, "read_cr8" }, \ { SVM_EXIT_READ_CR8, "read_cr8" }, \
{ SVM_EXIT_WRITE_CR0, "write_cr0" }, \ { SVM_EXIT_WRITE_CR0, "write_cr0" }, \
{ SVM_EXIT_WRITE_CR2, "write_cr2" }, \
{ SVM_EXIT_WRITE_CR3, "write_cr3" }, \ { SVM_EXIT_WRITE_CR3, "write_cr3" }, \
{ SVM_EXIT_WRITE_CR4, "write_cr4" }, \ { SVM_EXIT_WRITE_CR4, "write_cr4" }, \
{ SVM_EXIT_WRITE_CR8, "write_cr8" }, \ { SVM_EXIT_WRITE_CR8, "write_cr8" }, \
...@@ -91,26 +95,57 @@ ...@@ -91,26 +95,57 @@
{ SVM_EXIT_READ_DR1, "read_dr1" }, \ { SVM_EXIT_READ_DR1, "read_dr1" }, \
{ SVM_EXIT_READ_DR2, "read_dr2" }, \ { SVM_EXIT_READ_DR2, "read_dr2" }, \
{ SVM_EXIT_READ_DR3, "read_dr3" }, \ { SVM_EXIT_READ_DR3, "read_dr3" }, \
{ SVM_EXIT_READ_DR4, "read_dr4" }, \
{ SVM_EXIT_READ_DR5, "read_dr5" }, \
{ SVM_EXIT_READ_DR6, "read_dr6" }, \
{ SVM_EXIT_READ_DR7, "read_dr7" }, \
{ SVM_EXIT_WRITE_DR0, "write_dr0" }, \ { SVM_EXIT_WRITE_DR0, "write_dr0" }, \
{ SVM_EXIT_WRITE_DR1, "write_dr1" }, \ { SVM_EXIT_WRITE_DR1, "write_dr1" }, \
{ SVM_EXIT_WRITE_DR2, "write_dr2" }, \ { SVM_EXIT_WRITE_DR2, "write_dr2" }, \
{ SVM_EXIT_WRITE_DR3, "write_dr3" }, \ { SVM_EXIT_WRITE_DR3, "write_dr3" }, \
{ SVM_EXIT_WRITE_DR4, "write_dr4" }, \
{ SVM_EXIT_WRITE_DR5, "write_dr5" }, \ { SVM_EXIT_WRITE_DR5, "write_dr5" }, \
{ SVM_EXIT_WRITE_DR6, "write_dr6" }, \
{ SVM_EXIT_WRITE_DR7, "write_dr7" }, \ { SVM_EXIT_WRITE_DR7, "write_dr7" }, \
{ SVM_EXIT_EXCP_BASE + DE_VECTOR, "DE excp" }, \
{ SVM_EXIT_EXCP_BASE + DB_VECTOR, "DB excp" }, \ { SVM_EXIT_EXCP_BASE + DB_VECTOR, "DB excp" }, \
{ SVM_EXIT_EXCP_BASE + BP_VECTOR, "BP excp" }, \ { SVM_EXIT_EXCP_BASE + BP_VECTOR, "BP excp" }, \
{ SVM_EXIT_EXCP_BASE + OF_VECTOR, "OF excp" }, \
{ SVM_EXIT_EXCP_BASE + BR_VECTOR, "BR excp" }, \
{ SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" }, \ { SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" }, \
{ SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" }, \
{ SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" }, \ { SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" }, \
{ SVM_EXIT_EXCP_BASE + DF_VECTOR, "DF excp" }, \
{ SVM_EXIT_EXCP_BASE + TS_VECTOR, "TS excp" }, \
{ SVM_EXIT_EXCP_BASE + NP_VECTOR, "NP excp" }, \
{ SVM_EXIT_EXCP_BASE + SS_VECTOR, "SS excp" }, \
{ SVM_EXIT_EXCP_BASE + GP_VECTOR, "GP excp" }, \
{ SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" }, \
{ SVM_EXIT_EXCP_BASE + MF_VECTOR, "MF excp" }, \
{ SVM_EXIT_EXCP_BASE + AC_VECTOR, "AC excp" }, \ { SVM_EXIT_EXCP_BASE + AC_VECTOR, "AC excp" }, \
{ SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" }, \ { SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" }, \
{ SVM_EXIT_EXCP_BASE + XM_VECTOR, "XF excp" }, \
{ SVM_EXIT_INTR, "interrupt" }, \ { SVM_EXIT_INTR, "interrupt" }, \
{ SVM_EXIT_NMI, "nmi" }, \ { SVM_EXIT_NMI, "nmi" }, \
{ SVM_EXIT_SMI, "smi" }, \ { SVM_EXIT_SMI, "smi" }, \
{ SVM_EXIT_INIT, "init" }, \ { SVM_EXIT_INIT, "init" }, \
{ SVM_EXIT_VINTR, "vintr" }, \ { SVM_EXIT_VINTR, "vintr" }, \
{ SVM_EXIT_CR0_SEL_WRITE, "cr0_sel_write" }, \ { SVM_EXIT_CR0_SEL_WRITE, "cr0_sel_write" }, \
{ SVM_EXIT_IDTR_READ, "read_idtr" }, \
{ SVM_EXIT_GDTR_READ, "read_gdtr" }, \
{ SVM_EXIT_LDTR_READ, "read_ldtr" }, \
{ SVM_EXIT_TR_READ, "read_rt" }, \
{ SVM_EXIT_IDTR_WRITE, "write_idtr" }, \
{ SVM_EXIT_GDTR_WRITE, "write_gdtr" }, \
{ SVM_EXIT_LDTR_WRITE, "write_ldtr" }, \
{ SVM_EXIT_TR_WRITE, "write_rt" }, \
{ SVM_EXIT_RDTSC, "rdtsc" }, \
{ SVM_EXIT_RDPMC, "rdpmc" }, \
{ SVM_EXIT_PUSHF, "pushf" }, \
{ SVM_EXIT_POPF, "popf" }, \
{ SVM_EXIT_CPUID, "cpuid" }, \ { SVM_EXIT_CPUID, "cpuid" }, \
{ SVM_EXIT_RSM, "rsm" }, \
{ SVM_EXIT_IRET, "iret" }, \
{ SVM_EXIT_SWINT, "swint" }, \
{ SVM_EXIT_INVD, "invd" }, \ { SVM_EXIT_INVD, "invd" }, \
{ SVM_EXIT_PAUSE, "pause" }, \ { SVM_EXIT_PAUSE, "pause" }, \
{ SVM_EXIT_HLT, "hlt" }, \ { SVM_EXIT_HLT, "hlt" }, \
...@@ -119,6 +154,7 @@ ...@@ -119,6 +154,7 @@
{ SVM_EXIT_IOIO, "io" }, \ { SVM_EXIT_IOIO, "io" }, \
{ SVM_EXIT_MSR, "msr" }, \ { SVM_EXIT_MSR, "msr" }, \
{ SVM_EXIT_TASK_SWITCH, "task_switch" }, \ { SVM_EXIT_TASK_SWITCH, "task_switch" }, \
{ SVM_EXIT_FERR_FREEZE, "ferr_freeze" }, \
{ SVM_EXIT_SHUTDOWN, "shutdown" }, \ { SVM_EXIT_SHUTDOWN, "shutdown" }, \
{ SVM_EXIT_VMRUN, "vmrun" }, \ { SVM_EXIT_VMRUN, "vmrun" }, \
{ SVM_EXIT_VMMCALL, "hypercall" }, \ { SVM_EXIT_VMMCALL, "hypercall" }, \
...@@ -127,14 +163,16 @@ ...@@ -127,14 +163,16 @@
{ SVM_EXIT_STGI, "stgi" }, \ { SVM_EXIT_STGI, "stgi" }, \
{ SVM_EXIT_CLGI, "clgi" }, \ { SVM_EXIT_CLGI, "clgi" }, \
{ SVM_EXIT_SKINIT, "skinit" }, \ { SVM_EXIT_SKINIT, "skinit" }, \
{ SVM_EXIT_RDTSCP, "rdtscp" }, \
{ SVM_EXIT_ICEBP, "icebp" }, \
{ SVM_EXIT_WBINVD, "wbinvd" }, \ { SVM_EXIT_WBINVD, "wbinvd" }, \
{ SVM_EXIT_MONITOR, "monitor" }, \ { SVM_EXIT_MONITOR, "monitor" }, \
{ SVM_EXIT_MWAIT, "mwait" }, \ { SVM_EXIT_MWAIT, "mwait" }, \
{ SVM_EXIT_XSETBV, "xsetbv" }, \ { SVM_EXIT_XSETBV, "xsetbv" }, \
{ SVM_EXIT_NPF, "npf" }, \ { SVM_EXIT_NPF, "npf" }, \
{ SVM_EXIT_RSM, "rsm" }, \
{ SVM_EXIT_AVIC_INCOMPLETE_IPI, "avic_incomplete_ipi" }, \ { SVM_EXIT_AVIC_INCOMPLETE_IPI, "avic_incomplete_ipi" }, \
{ SVM_EXIT_AVIC_UNACCELERATED_ACCESS, "avic_unaccelerated_access" } { SVM_EXIT_AVIC_UNACCELERATED_ACCESS, "avic_unaccelerated_access" }, \
{ SVM_EXIT_ERR, "invalid_guest_state" }
#endif /* _UAPI__SVM_H */ #endif /* _UAPI__SVM_H */
...@@ -84,7 +84,7 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id); ...@@ -84,7 +84,7 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id);
#define TSC_RATIO_MIN 0x0000000000000001ULL #define TSC_RATIO_MIN 0x0000000000000001ULL
#define TSC_RATIO_MAX 0x000000ffffffffffULL #define TSC_RATIO_MAX 0x000000ffffffffffULL
#define AVIC_HPA_MASK ~((0xFFFULL << 52) || 0xFFF) #define AVIC_HPA_MASK ~((0xFFFULL << 52) | 0xFFF)
/* /*
* 0xff is broadcast, so the max index allowed for physical APIC ID * 0xff is broadcast, so the max index allowed for physical APIC ID
...@@ -3597,7 +3597,7 @@ static int avic_incomplete_ipi_interception(struct vcpu_svm *svm) ...@@ -3597,7 +3597,7 @@ static int avic_incomplete_ipi_interception(struct vcpu_svm *svm)
u32 icrh = svm->vmcb->control.exit_info_1 >> 32; u32 icrh = svm->vmcb->control.exit_info_1 >> 32;
u32 icrl = svm->vmcb->control.exit_info_1; u32 icrl = svm->vmcb->control.exit_info_1;
u32 id = svm->vmcb->control.exit_info_2 >> 32; u32 id = svm->vmcb->control.exit_info_2 >> 32;
u32 index = svm->vmcb->control.exit_info_2 && 0xFF; u32 index = svm->vmcb->control.exit_info_2 & 0xFF;
struct kvm_lapic *apic = svm->vcpu.arch.apic; struct kvm_lapic *apic = svm->vcpu.arch.apic;
trace_kvm_avic_incomplete_ipi(svm->vcpu.vcpu_id, icrh, icrl, id, index); trace_kvm_avic_incomplete_ipi(svm->vcpu.vcpu_id, icrh, icrl, id, index);
......
...@@ -2418,7 +2418,9 @@ static void vmx_set_msr_bitmap(struct kvm_vcpu *vcpu) ...@@ -2418,7 +2418,9 @@ static void vmx_set_msr_bitmap(struct kvm_vcpu *vcpu)
if (is_guest_mode(vcpu)) if (is_guest_mode(vcpu))
msr_bitmap = vmx_msr_bitmap_nested; msr_bitmap = vmx_msr_bitmap_nested;
else if (vcpu->arch.apic_base & X2APIC_ENABLE) { else if (cpu_has_secondary_exec_ctrls() &&
(vmcs_read32(SECONDARY_VM_EXEC_CONTROL) &
SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE)) {
if (is_long_mode(vcpu)) if (is_long_mode(vcpu))
msr_bitmap = vmx_msr_bitmap_longmode_x2apic; msr_bitmap = vmx_msr_bitmap_longmode_x2apic;
else else
...@@ -4787,6 +4789,19 @@ static void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu) ...@@ -4787,6 +4789,19 @@ static void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
struct vcpu_vmx *vmx = to_vmx(vcpu); struct vcpu_vmx *vmx = to_vmx(vcpu);
vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_ctrl(vmx)); vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_ctrl(vmx));
if (cpu_has_secondary_exec_ctrls()) {
if (kvm_vcpu_apicv_active(vcpu))
vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
SECONDARY_EXEC_APIC_REGISTER_VIRT |
SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
else
vmcs_clear_bits(SECONDARY_VM_EXEC_CONTROL,
SECONDARY_EXEC_APIC_REGISTER_VIRT |
SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
}
if (cpu_has_vmx_msr_bitmap())
vmx_set_msr_bitmap(vcpu);
} }
static u32 vmx_exec_control(struct vcpu_vmx *vmx) static u32 vmx_exec_control(struct vcpu_vmx *vmx)
...@@ -6333,13 +6348,11 @@ static __init int hardware_setup(void) ...@@ -6333,13 +6348,11 @@ static __init int hardware_setup(void)
set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */ set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */
if (enable_apicv) {
for (msr = 0x800; msr <= 0x8ff; msr++) for (msr = 0x800; msr <= 0x8ff; msr++)
vmx_disable_intercept_msr_read_x2apic(msr); vmx_disable_intercept_msr_read_x2apic(msr);
/* According SDM, in x2apic mode, the whole id reg is used. /* According SDM, in x2apic mode, the whole id reg is used. But in
* But in KVM, it only use the highest eight bits. Need to * KVM, it only use the highest eight bits. Need to intercept it */
* intercept it */
vmx_enable_intercept_msr_read_x2apic(0x802); vmx_enable_intercept_msr_read_x2apic(0x802);
/* TMCCT */ /* TMCCT */
vmx_enable_intercept_msr_read_x2apic(0x839); vmx_enable_intercept_msr_read_x2apic(0x839);
...@@ -6349,7 +6362,6 @@ static __init int hardware_setup(void) ...@@ -6349,7 +6362,6 @@ static __init int hardware_setup(void)
vmx_disable_intercept_msr_write_x2apic(0x80b); vmx_disable_intercept_msr_write_x2apic(0x80b);
/* SELF-IPI */ /* SELF-IPI */
vmx_disable_intercept_msr_write_x2apic(0x83f); vmx_disable_intercept_msr_write_x2apic(0x83f);
}
if (enable_ept) { if (enable_ept) {
kvm_mmu_set_mask_ptes(0ull, kvm_mmu_set_mask_ptes(0ull,
......
...@@ -24,9 +24,6 @@ ...@@ -24,9 +24,6 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
struct arch_timer_kvm { struct arch_timer_kvm {
/* Is the timer enabled */
bool enabled;
/* Virtual offset */ /* Virtual offset */
cycle_t cntvoff; cycle_t cntvoff;
}; };
...@@ -53,15 +50,15 @@ struct arch_timer_cpu { ...@@ -53,15 +50,15 @@ struct arch_timer_cpu {
/* Timer IRQ */ /* Timer IRQ */
struct kvm_irq_level irq; struct kvm_irq_level irq;
/* VGIC mapping */
struct irq_phys_map *map;
/* Active IRQ state caching */ /* Active IRQ state caching */
bool active_cleared_last; bool active_cleared_last;
/* Is the timer enabled */
bool enabled;
}; };
int kvm_timer_hyp_init(void); int kvm_timer_hyp_init(void);
void kvm_timer_enable(struct kvm *kvm); int kvm_timer_enable(struct kvm_vcpu *vcpu);
void kvm_timer_init(struct kvm *kvm); void kvm_timer_init(struct kvm *kvm);
int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu, int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
const struct kvm_irq_level *irq); const struct kvm_irq_level *irq);
......
...@@ -19,6 +19,10 @@ ...@@ -19,6 +19,10 @@
#ifndef __ASM_ARM_KVM_VGIC_H #ifndef __ASM_ARM_KVM_VGIC_H
#define __ASM_ARM_KVM_VGIC_H #define __ASM_ARM_KVM_VGIC_H
#ifdef CONFIG_KVM_NEW_VGIC
#include <kvm/vgic/vgic.h>
#else
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kvm.h> #include <linux/kvm.h>
#include <linux/irqreturn.h> #include <linux/irqreturn.h>
...@@ -158,7 +162,6 @@ struct vgic_io_device { ...@@ -158,7 +162,6 @@ struct vgic_io_device {
struct irq_phys_map { struct irq_phys_map {
u32 virt_irq; u32 virt_irq;
u32 phys_irq; u32 phys_irq;
u32 irq;
}; };
struct irq_phys_map_entry { struct irq_phys_map_entry {
...@@ -305,9 +308,6 @@ struct vgic_cpu { ...@@ -305,9 +308,6 @@ struct vgic_cpu {
unsigned long *active_shared; unsigned long *active_shared;
unsigned long *pend_act_shared; unsigned long *pend_act_shared;
/* Number of list registers on this CPU */
int nr_lr;
/* CPU vif control registers for world switch */ /* CPU vif control registers for world switch */
union { union {
struct vgic_v2_cpu_if vgic_v2; struct vgic_v2_cpu_if vgic_v2;
...@@ -342,17 +342,18 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu); ...@@ -342,17 +342,18 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num, int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
bool level); bool level);
int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
struct irq_phys_map *map, bool level); unsigned int virt_irq, bool level);
void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg); void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu); int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, int virt_irq, int phys_irq);
int virt_irq, int irq); int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map); bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
#define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel)) #define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel))
#define vgic_initialized(k) (!!((k)->arch.vgic.nr_cpus)) #define vgic_initialized(k) (!!((k)->arch.vgic.nr_cpus))
#define vgic_ready(k) ((k)->arch.vgic.ready) #define vgic_ready(k) ((k)->arch.vgic.ready)
#define vgic_valid_spi(k, i) (((i) >= VGIC_NR_PRIVATE_IRQS) && \
((i) < (k)->arch.vgic.nr_irqs))
int vgic_v2_probe(const struct gic_kvm_info *gic_kvm_info, int vgic_v2_probe(const struct gic_kvm_info *gic_kvm_info,
const struct vgic_ops **ops, const struct vgic_ops **ops,
...@@ -370,4 +371,5 @@ static inline int vgic_v3_probe(const struct gic_kvm_info *gic_kvm_info, ...@@ -370,4 +371,5 @@ static inline int vgic_v3_probe(const struct gic_kvm_info *gic_kvm_info,
} }
#endif #endif
#endif /* old VGIC include */
#endif #endif
/*
* Copyright (C) 2015, 2016 ARM Ltd.
*
* 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 __ASM_ARM_KVM_VGIC_VGIC_H
#define __ASM_ARM_KVM_VGIC_VGIC_H
#include <linux/kernel.h>
#include <linux/kvm.h>
#include <linux/irqreturn.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <kvm/iodev.h>
#define VGIC_V3_MAX_CPUS 255
#define VGIC_V2_MAX_CPUS 8
#define VGIC_NR_IRQS_LEGACY 256
#define VGIC_NR_SGIS 16
#define VGIC_NR_PPIS 16
#define VGIC_NR_PRIVATE_IRQS (VGIC_NR_SGIS + VGIC_NR_PPIS)
#define VGIC_MAX_PRIVATE (VGIC_NR_PRIVATE_IRQS - 1)
#define VGIC_MAX_SPI 1019
#define VGIC_MAX_RESERVED 1023
#define VGIC_MIN_LPI 8192
enum vgic_type {
VGIC_V2, /* Good ol' GICv2 */
VGIC_V3, /* New fancy GICv3 */
};
/* same for all guests, as depending only on the _host's_ GIC model */
struct vgic_global {
/* type of the host GIC */
enum vgic_type type;
/* Physical address of vgic virtual cpu interface */
phys_addr_t vcpu_base;
/* virtual control interface mapping */
void __iomem *vctrl_base;
/* Number of implemented list registers */
int nr_lr;
/* Maintenance IRQ number */
unsigned int maint_irq;
/* maximum number of VCPUs allowed (GICv2 limits us to 8) */
int max_gic_vcpus;
/* Only needed for the legacy KVM_CREATE_IRQCHIP */
bool can_emulate_gicv2;
};
extern struct vgic_global kvm_vgic_global_state;
#define VGIC_V2_MAX_LRS (1 << 6)
#define VGIC_V3_MAX_LRS 16
#define VGIC_V3_LR_INDEX(lr) (VGIC_V3_MAX_LRS - 1 - lr)
enum vgic_irq_config {
VGIC_CONFIG_EDGE = 0,
VGIC_CONFIG_LEVEL
};
struct vgic_irq {
spinlock_t irq_lock; /* Protects the content of the struct */
struct list_head ap_list;
struct kvm_vcpu *vcpu; /* SGIs and PPIs: The VCPU
* SPIs and LPIs: The VCPU whose ap_list
* this is queued on.
*/
struct kvm_vcpu *target_vcpu; /* The VCPU that this interrupt should
* be sent to, as a result of the
* targets reg (v2) or the
* affinity reg (v3).
*/
u32 intid; /* Guest visible INTID */
bool pending;
bool line_level; /* Level only */
bool soft_pending; /* Level only */
bool active; /* not used for LPIs */
bool enabled;
bool hw; /* Tied to HW IRQ */
u32 hwintid; /* HW INTID number */
union {
u8 targets; /* GICv2 target VCPUs mask */
u32 mpidr; /* GICv3 target VCPU */
};
u8 source; /* GICv2 SGIs only */
u8 priority;
enum vgic_irq_config config; /* Level or edge */
};
struct vgic_register_region;
struct vgic_io_device {
gpa_t base_addr;
struct kvm_vcpu *redist_vcpu;
const struct vgic_register_region *regions;
int nr_regions;
struct kvm_io_device dev;
};
struct vgic_dist {
bool in_kernel;
bool ready;
bool initialized;
/* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
u32 vgic_model;
int nr_spis;
/* TODO: Consider moving to global state */
/* Virtual control interface mapping */
void __iomem *vctrl_base;
/* base addresses in guest physical address space: */
gpa_t vgic_dist_base; /* distributor */
union {
/* either a GICv2 CPU interface */
gpa_t vgic_cpu_base;
/* or a number of GICv3 redistributor regions */
gpa_t vgic_redist_base;
};
/* distributor enabled */
bool enabled;
struct vgic_irq *spis;
struct vgic_io_device dist_iodev;
struct vgic_io_device *redist_iodevs;
};
struct vgic_v2_cpu_if {
u32 vgic_hcr;
u32 vgic_vmcr;
u32 vgic_misr; /* Saved only */
u64 vgic_eisr; /* Saved only */
u64 vgic_elrsr; /* Saved only */
u32 vgic_apr;
u32 vgic_lr[VGIC_V2_MAX_LRS];
};
struct vgic_v3_cpu_if {
#ifdef CONFIG_KVM_ARM_VGIC_V3
u32 vgic_hcr;
u32 vgic_vmcr;
u32 vgic_sre; /* Restored only, change ignored */
u32 vgic_misr; /* Saved only */
u32 vgic_eisr; /* Saved only */
u32 vgic_elrsr; /* Saved only */
u32 vgic_ap0r[4];
u32 vgic_ap1r[4];
u64 vgic_lr[VGIC_V3_MAX_LRS];
#endif
};
struct vgic_cpu {
/* CPU vif control registers for world switch */
union {
struct vgic_v2_cpu_if vgic_v2;
struct vgic_v3_cpu_if vgic_v3;
};
unsigned int used_lrs;
struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
spinlock_t ap_list_lock; /* Protects the ap_list */
/*
* List of IRQs that this VCPU should consider because they are either
* Active or Pending (hence the name; AP list), or because they recently
* were one of the two and need to be migrated off this list to another
* VCPU.
*/
struct list_head ap_list_head;
u64 live_lrs;
};
int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
void kvm_vgic_early_init(struct kvm *kvm);
int kvm_vgic_create(struct kvm *kvm, u32 type);
void kvm_vgic_destroy(struct kvm *kvm);
void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu);
int kvm_vgic_map_resources(struct kvm *kvm);
int kvm_vgic_hyp_init(void);
int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid,
bool level);
int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, unsigned int intid,
bool level);
int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, u32 virt_irq, u32 phys_irq);
int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq);
bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq);
int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
#define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel))
#define vgic_initialized(k) ((k)->arch.vgic.initialized)
#define vgic_ready(k) ((k)->arch.vgic.ready)
#define vgic_valid_spi(k, i) (((i) >= VGIC_NR_PRIVATE_IRQS) && \
((i) < (k)->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS))
bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
#ifdef CONFIG_KVM_ARM_VGIC_V3
void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
#else
static inline void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg)
{
}
#endif
/**
* kvm_vgic_get_max_vcpus - Get the maximum number of VCPUs allowed by HW
*
* The host's GIC naturally limits the maximum amount of VCPUs a guest
* can use.
*/
static inline int kvm_vgic_get_max_vcpus(void)
{
return kvm_vgic_global_state.max_gic_vcpus;
}
#endif /* __ASM_ARM_KVM_VGIC_VGIC_H */
...@@ -273,6 +273,12 @@ ...@@ -273,6 +273,12 @@
#define ICH_LR_ACTIVE_BIT (1ULL << 63) #define ICH_LR_ACTIVE_BIT (1ULL << 63)
#define ICH_LR_PHYS_ID_SHIFT 32 #define ICH_LR_PHYS_ID_SHIFT 32
#define ICH_LR_PHYS_ID_MASK (0x3ffULL << ICH_LR_PHYS_ID_SHIFT) #define ICH_LR_PHYS_ID_MASK (0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
#define ICH_LR_PRIORITY_SHIFT 48
/* These are for GICv2 emulation only */
#define GICH_LR_VIRTUALID (0x3ffUL << 0)
#define GICH_LR_PHYSID_CPUID_SHIFT (10)
#define GICH_LR_PHYSID_CPUID (7UL << GICH_LR_PHYSID_CPUID_SHIFT)
#define ICH_MISR_EOI (1 << 0) #define ICH_MISR_EOI (1 << 0)
#define ICH_MISR_U (1 << 1) #define ICH_MISR_U (1 << 1)
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#define GIC_DIST_CTRL 0x000 #define GIC_DIST_CTRL 0x000
#define GIC_DIST_CTR 0x004 #define GIC_DIST_CTR 0x004
#define GIC_DIST_IIDR 0x008
#define GIC_DIST_IGROUP 0x080 #define GIC_DIST_IGROUP 0x080
#define GIC_DIST_ENABLE_SET 0x100 #define GIC_DIST_ENABLE_SET 0x100
#define GIC_DIST_ENABLE_CLEAR 0x180 #define GIC_DIST_ENABLE_CLEAR 0x180
...@@ -76,6 +77,7 @@ ...@@ -76,6 +77,7 @@
#define GICH_LR_VIRTUALID (0x3ff << 0) #define GICH_LR_VIRTUALID (0x3ff << 0)
#define GICH_LR_PHYSID_CPUID_SHIFT (10) #define GICH_LR_PHYSID_CPUID_SHIFT (10)
#define GICH_LR_PHYSID_CPUID (0x3ff << GICH_LR_PHYSID_CPUID_SHIFT) #define GICH_LR_PHYSID_CPUID (0x3ff << GICH_LR_PHYSID_CPUID_SHIFT)
#define GICH_LR_PRIORITY_SHIFT 23
#define GICH_LR_STATE (3 << 28) #define GICH_LR_STATE (3 << 28)
#define GICH_LR_PENDING_BIT (1 << 28) #define GICH_LR_PENDING_BIT (1 << 28)
#define GICH_LR_ACTIVE_BIT (1 << 29) #define GICH_LR_ACTIVE_BIT (1 << 29)
......
...@@ -412,6 +412,8 @@ struct kvm { ...@@ -412,6 +412,8 @@ struct kvm {
#endif #endif
long tlbs_dirty; long tlbs_dirty;
struct list_head devices; struct list_head devices;
struct dentry *debugfs_dentry;
struct kvm_stat_data **debugfs_stat_data;
}; };
#define kvm_err(fmt, ...) \ #define kvm_err(fmt, ...) \
...@@ -991,6 +993,11 @@ enum kvm_stat_kind { ...@@ -991,6 +993,11 @@ enum kvm_stat_kind {
KVM_STAT_VCPU, KVM_STAT_VCPU,
}; };
struct kvm_stat_data {
int offset;
struct kvm *kvm;
};
struct kvm_stats_debugfs_item { struct kvm_stats_debugfs_item {
const char *name; const char *name;
int offset; int offset;
......
...@@ -108,7 +108,7 @@ TRACE_EVENT(kvm_ioapic_set_irq, ...@@ -108,7 +108,7 @@ TRACE_EVENT(kvm_ioapic_set_irq,
__entry->coalesced = coalesced; __entry->coalesced = coalesced;
), ),
TP_printk("pin %u dst %x vec=%u (%s|%s|%s%s)%s", TP_printk("pin %u dst %x vec %u (%s|%s|%s%s)%s",
__entry->pin, (u8)(__entry->e >> 56), (u8)__entry->e, __entry->pin, (u8)(__entry->e >> 56), (u8)__entry->e,
__print_symbolic((__entry->e >> 8 & 0x7), kvm_deliver_mode), __print_symbolic((__entry->e >> 8 & 0x7), kvm_deliver_mode),
(__entry->e & (1<<11)) ? "logical" : "physical", (__entry->e & (1<<11)) ? "logical" : "physical",
...@@ -129,7 +129,7 @@ TRACE_EVENT(kvm_ioapic_delayed_eoi_inj, ...@@ -129,7 +129,7 @@ TRACE_EVENT(kvm_ioapic_delayed_eoi_inj,
__entry->e = e; __entry->e = e;
), ),
TP_printk("dst %x vec=%u (%s|%s|%s%s)", TP_printk("dst %x vec %u (%s|%s|%s%s)",
(u8)(__entry->e >> 56), (u8)__entry->e, (u8)(__entry->e >> 56), (u8)__entry->e,
__print_symbolic((__entry->e >> 8 & 0x7), kvm_deliver_mode), __print_symbolic((__entry->e >> 8 & 0x7), kvm_deliver_mode),
(__entry->e & (1<<11)) ? "logical" : "physical", (__entry->e & (1<<11)) ? "logical" : "physical",
...@@ -151,7 +151,7 @@ TRACE_EVENT(kvm_msi_set_irq, ...@@ -151,7 +151,7 @@ TRACE_EVENT(kvm_msi_set_irq,
__entry->data = data; __entry->data = data;
), ),
TP_printk("dst %u vec %x (%s|%s|%s%s)", TP_printk("dst %u vec %u (%s|%s|%s%s)",
(u8)(__entry->address >> 12), (u8)__entry->data, (u8)(__entry->address >> 12), (u8)__entry->data,
__print_symbolic((__entry->data >> 8 & 0x7), kvm_deliver_mode), __print_symbolic((__entry->data >> 8 & 0x7), kvm_deliver_mode),
(__entry->address & (1<<2)) ? "logical" : "physical", (__entry->address & (1<<2)) ? "logical" : "physical",
......
...@@ -16,6 +16,7 @@ help: ...@@ -16,6 +16,7 @@ help:
@echo ' gpio - GPIO tools' @echo ' gpio - GPIO tools'
@echo ' hv - tools used when in Hyper-V clients' @echo ' hv - tools used when in Hyper-V clients'
@echo ' iio - IIO tools' @echo ' iio - IIO tools'
@echo ' kvm_stat - top-like utility for displaying kvm statistics'
@echo ' lguest - a minimal 32-bit x86 hypervisor' @echo ' lguest - a minimal 32-bit x86 hypervisor'
@echo ' net - misc networking tools' @echo ' net - misc networking tools'
@echo ' perf - Linux performance measurement and analysis tool' @echo ' perf - Linux performance measurement and analysis tool'
...@@ -110,10 +111,13 @@ tmon_install: ...@@ -110,10 +111,13 @@ tmon_install:
freefall_install: freefall_install:
$(call descend,laptop/$(@:_install=),install) $(call descend,laptop/$(@:_install=),install)
kvm_stat_install:
$(call descend,kvm/$(@:_install=),install)
install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \ install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \
perf_install selftests_install turbostat_install usb_install \ perf_install selftests_install turbostat_install usb_install \
virtio_install vm_install net_install x86_energy_perf_policy_install \ virtio_install vm_install net_install x86_energy_perf_policy_install \
tmon_install freefall_install objtool_install tmon_install freefall_install objtool_install kvm_stat_install
acpi_clean: acpi_clean:
$(call descend,power/acpi,clean) $(call descend,power/acpi,clean)
......
include ../../scripts/Makefile.include
include ../../scripts/utilities.mak
BINDIR=usr/bin
MANDIR=usr/share/man
MAN1DIR=$(MANDIR)/man1
MAN1=kvm_stat.1
A2X=a2x
a2x_path := $(call get-executable,$(A2X))
all: man
ifneq ($(findstring $(MAKEFLAGS),s),s)
ifneq ($(V),1)
QUIET_A2X = @echo ' A2X '$@;
endif
endif
%.1: %.txt
ifeq ($(a2x_path),)
$(error "You need to install asciidoc for man pages")
else
$(QUIET_A2X)$(A2X) --doctype manpage --format manpage $<
endif
clean:
rm -f $(MAN1)
man: $(MAN1)
install-man: man
install -d -m 755 $(INSTALL_ROOT)/$(MAN1DIR)
install -m 644 kvm_stat.1 $(INSTALL_ROOT)/$(MAN1DIR)
install-tools:
install -d -m 755 $(INSTALL_ROOT)/$(BINDIR)
install -m 755 -p "kvm_stat" "$(INSTALL_ROOT)/$(BINDIR)/$(TARGET)"
install: install-tools install-man
.PHONY: all clean man install-tools install-man install
This diff is collapsed.
kvm_stat(1)
===========
NAME
----
kvm_stat - Report KVM kernel module event counters
SYNOPSIS
--------
[verse]
'kvm_stat' [OPTION]...
DESCRIPTION
-----------
kvm_stat prints counts of KVM kernel module trace events. These events signify
state transitions such as guest mode entry and exit.
This tool is useful for observing guest behavior from the host perspective.
Often conclusions about performance or buggy behavior can be drawn from the
output.
The set of KVM kernel module trace events may be specific to the kernel version
or architecture. It is best to check the KVM kernel module source code for the
meaning of events.
OPTIONS
-------
-1::
--once::
--batch::
run in batch mode for one second
-l::
--log::
run in logging mode (like vmstat)
-t::
--tracepoints::
retrieve statistics from tracepoints
-d::
--debugfs::
retrieve statistics from debugfs
-p<pid>::
--pid=<pid>::
limit statistics to one virtual machine (pid)
-f<fields>::
--fields=<fields>::
fields to display (regex)
-h::
--help::
show help message
SEE ALSO
--------
'perf'(1), 'trace-cmd'(1)
AUTHOR
------
Stefan Hajnoczi <stefanha@redhat.com>
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/kvm.h> #include <linux/kvm.h>
#include <linux/kvm_host.h> #include <linux/kvm_host.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h>
#include <clocksource/arm_arch_timer.h> #include <clocksource/arm_arch_timer.h>
#include <asm/arch_timer.h> #include <asm/arch_timer.h>
...@@ -174,10 +175,10 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level) ...@@ -174,10 +175,10 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
timer->active_cleared_last = false; timer->active_cleared_last = false;
timer->irq.level = new_level; timer->irq.level = new_level;
trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->map->virt_irq, trace_kvm_timer_update_irq(vcpu->vcpu_id, timer->irq.irq,
timer->irq.level); timer->irq.level);
ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id, ret = kvm_vgic_inject_mapped_irq(vcpu->kvm, vcpu->vcpu_id,
timer->map, timer->irq.irq,
timer->irq.level); timer->irq.level);
WARN_ON(ret); WARN_ON(ret);
} }
...@@ -196,7 +197,7 @@ static int kvm_timer_update_state(struct kvm_vcpu *vcpu) ...@@ -196,7 +197,7 @@ static int kvm_timer_update_state(struct kvm_vcpu *vcpu)
* because the guest would never see the interrupt. Instead wait * because the guest would never see the interrupt. Instead wait
* until we call this function from kvm_timer_flush_hwstate. * until we call this function from kvm_timer_flush_hwstate.
*/ */
if (!vgic_initialized(vcpu->kvm)) if (!vgic_initialized(vcpu->kvm) || !timer->enabled)
return -ENODEV; return -ENODEV;
if (kvm_timer_should_fire(vcpu) != timer->irq.level) if (kvm_timer_should_fire(vcpu) != timer->irq.level)
...@@ -274,10 +275,8 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu) ...@@ -274,10 +275,8 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
* to ensure that hardware interrupts from the timer triggers a guest * to ensure that hardware interrupts from the timer triggers a guest
* exit. * exit.
*/ */
if (timer->irq.level || kvm_vgic_map_is_active(vcpu, timer->map)) phys_active = timer->irq.level ||
phys_active = true; kvm_vgic_map_is_active(vcpu, timer->irq.irq);
else
phys_active = false;
/* /*
* We want to avoid hitting the (re)distributor as much as * We want to avoid hitting the (re)distributor as much as
...@@ -302,7 +301,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu) ...@@ -302,7 +301,7 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
if (timer->active_cleared_last && !phys_active) if (timer->active_cleared_last && !phys_active)
return; return;
ret = irq_set_irqchip_state(timer->map->irq, ret = irq_set_irqchip_state(host_vtimer_irq,
IRQCHIP_STATE_ACTIVE, IRQCHIP_STATE_ACTIVE,
phys_active); phys_active);
WARN_ON(ret); WARN_ON(ret);
...@@ -334,7 +333,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu, ...@@ -334,7 +333,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
const struct kvm_irq_level *irq) const struct kvm_irq_level *irq)
{ {
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
struct irq_phys_map *map;
/* /*
* The vcpu timer irq number cannot be determined in * The vcpu timer irq number cannot be determined in
...@@ -353,15 +351,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu, ...@@ -353,15 +351,6 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
timer->cntv_ctl = 0; timer->cntv_ctl = 0;
kvm_timer_update_state(vcpu); kvm_timer_update_state(vcpu);
/*
* Tell the VGIC that the virtual interrupt is tied to a
* physical interrupt. We do that once per VCPU.
*/
map = kvm_vgic_map_phys_irq(vcpu, irq->irq, host_vtimer_irq);
if (WARN_ON(IS_ERR(map)))
return PTR_ERR(map);
timer->map = map;
return 0; return 0;
} }
...@@ -487,14 +476,43 @@ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu) ...@@ -487,14 +476,43 @@ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
timer_disarm(timer); timer_disarm(timer);
if (timer->map) kvm_vgic_unmap_phys_irq(vcpu, timer->irq.irq);
kvm_vgic_unmap_phys_irq(vcpu, timer->map);
} }
void kvm_timer_enable(struct kvm *kvm) int kvm_timer_enable(struct kvm_vcpu *vcpu)
{ {
if (kvm->arch.timer.enabled) struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
return; struct irq_desc *desc;
struct irq_data *data;
int phys_irq;
int ret;
if (timer->enabled)
return 0;
/*
* Find the physical IRQ number corresponding to the host_vtimer_irq
*/
desc = irq_to_desc(host_vtimer_irq);
if (!desc) {
kvm_err("%s: no interrupt descriptor\n", __func__);
return -EINVAL;
}
data = irq_desc_get_irq_data(desc);
while (data->parent_data)
data = data->parent_data;
phys_irq = data->hwirq;
/*
* Tell the VGIC that the virtual interrupt is tied to a
* physical interrupt. We do that once per VCPU.
*/
ret = kvm_vgic_map_phys_irq(vcpu, timer->irq.irq, phys_irq);
if (ret)
return ret;
/* /*
* There is a potential race here between VCPUs starting for the first * There is a potential race here between VCPUs starting for the first
...@@ -505,7 +523,9 @@ void kvm_timer_enable(struct kvm *kvm) ...@@ -505,7 +523,9 @@ void kvm_timer_enable(struct kvm *kvm)
* the arch timers are enabled. * the arch timers are enabled.
*/ */
if (timecounter && wqueue) if (timecounter && wqueue)
kvm->arch.timer.enabled = 1; timer->enabled = 1;
return 0;
} }
void kvm_timer_init(struct kvm *kvm) void kvm_timer_init(struct kvm *kvm)
......
...@@ -24,11 +24,10 @@ ...@@ -24,11 +24,10 @@
/* vcpu is already in the HYP VA space */ /* vcpu is already in the HYP VA space */
void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu) void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu)
{ {
struct kvm *kvm = kern_hyp_va(vcpu->kvm);
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
u64 val; u64 val;
if (kvm->arch.timer.enabled) { if (timer->enabled) {
timer->cntv_ctl = read_sysreg_el0(cntv_ctl); timer->cntv_ctl = read_sysreg_el0(cntv_ctl);
timer->cntv_cval = read_sysreg_el0(cntv_cval); timer->cntv_cval = read_sysreg_el0(cntv_cval);
} }
...@@ -60,7 +59,7 @@ void __hyp_text __timer_restore_state(struct kvm_vcpu *vcpu) ...@@ -60,7 +59,7 @@ void __hyp_text __timer_restore_state(struct kvm_vcpu *vcpu)
val |= CNTHCTL_EL1PCTEN; val |= CNTHCTL_EL1PCTEN;
write_sysreg(val, cnthctl_el2); write_sysreg(val, cnthctl_el2);
if (kvm->arch.timer.enabled) { if (timer->enabled) {
write_sysreg(kvm->arch.timer.cntvoff, cntvoff_el2); write_sysreg(kvm->arch.timer.cntvoff, cntvoff_el2);
write_sysreg_el0(timer->cntv_cval, cntv_cval); write_sysreg_el0(timer->cntv_cval, cntv_cval);
isb(); isb();
......
...@@ -21,11 +21,18 @@ ...@@ -21,11 +21,18 @@
#include <asm/kvm_hyp.h> #include <asm/kvm_hyp.h>
#ifdef CONFIG_KVM_NEW_VGIC
extern struct vgic_global kvm_vgic_global_state;
#define vgic_v2_params kvm_vgic_global_state
#else
extern struct vgic_params vgic_v2_params;
#endif
static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu, static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
void __iomem *base) void __iomem *base)
{ {
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2; struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
int nr_lr = vcpu->arch.vgic_cpu.nr_lr; int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
u32 eisr0, eisr1; u32 eisr0, eisr1;
int i; int i;
bool expect_mi; bool expect_mi;
...@@ -67,7 +74,7 @@ static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu, ...@@ -67,7 +74,7 @@ static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base) static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
{ {
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2; struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
int nr_lr = vcpu->arch.vgic_cpu.nr_lr; int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
u32 elrsr0, elrsr1; u32 elrsr0, elrsr1;
elrsr0 = readl_relaxed(base + GICH_ELRSR0); elrsr0 = readl_relaxed(base + GICH_ELRSR0);
...@@ -86,7 +93,7 @@ static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base) ...@@ -86,7 +93,7 @@ static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
static void __hyp_text save_lrs(struct kvm_vcpu *vcpu, void __iomem *base) static void __hyp_text save_lrs(struct kvm_vcpu *vcpu, void __iomem *base)
{ {
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2; struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
int nr_lr = vcpu->arch.vgic_cpu.nr_lr; int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
int i; int i;
for (i = 0; i < nr_lr; i++) { for (i = 0; i < nr_lr; i++) {
...@@ -141,13 +148,13 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu) ...@@ -141,13 +148,13 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2; struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
struct vgic_dist *vgic = &kvm->arch.vgic; struct vgic_dist *vgic = &kvm->arch.vgic;
void __iomem *base = kern_hyp_va(vgic->vctrl_base); void __iomem *base = kern_hyp_va(vgic->vctrl_base);
int i, nr_lr; int nr_lr = (kern_hyp_va(&vgic_v2_params))->nr_lr;
int i;
u64 live_lrs = 0; u64 live_lrs = 0;
if (!base) if (!base)
return; return;
nr_lr = vcpu->arch.vgic_cpu.nr_lr;
for (i = 0; i < nr_lr; i++) for (i = 0; i < nr_lr; i++)
if (cpu_if->vgic_lr[i] & GICH_LR_STATE) if (cpu_if->vgic_lr[i] & GICH_LR_STATE)
......
...@@ -436,7 +436,14 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu) ...@@ -436,7 +436,14 @@ static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu)
return 0; return 0;
} }
static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi) #define irq_is_ppi(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
/*
* For one VM the interrupt type must be same for each vcpu.
* As a PPI, the interrupt number is the same for all vcpus,
* while as an SPI it must be a separate number per vcpu.
*/
static bool pmu_irq_is_valid(struct kvm *kvm, int irq)
{ {
int i; int i;
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu;
...@@ -445,7 +452,7 @@ static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi) ...@@ -445,7 +452,7 @@ static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi)
if (!kvm_arm_pmu_irq_initialized(vcpu)) if (!kvm_arm_pmu_irq_initialized(vcpu))
continue; continue;
if (is_ppi) { if (irq_is_ppi(irq)) {
if (vcpu->arch.pmu.irq_num != irq) if (vcpu->arch.pmu.irq_num != irq)
return false; return false;
} else { } else {
...@@ -457,7 +464,6 @@ static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi) ...@@ -457,7 +464,6 @@ static bool irq_is_valid(struct kvm *kvm, int irq, bool is_ppi)
return true; return true;
} }
int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
{ {
switch (attr->attr) { switch (attr->attr) {
...@@ -471,14 +477,11 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) ...@@ -471,14 +477,11 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
if (get_user(irq, uaddr)) if (get_user(irq, uaddr))
return -EFAULT; return -EFAULT;
/* /* The PMU overflow interrupt can be a PPI or a valid SPI. */
* The PMU overflow interrupt could be a PPI or SPI, but for one if (!(irq_is_ppi(irq) || vgic_valid_spi(vcpu->kvm, irq)))
* VM the interrupt type must be same for each vcpu. As a PPI, return -EINVAL;
* the interrupt number is the same for all vcpus, while as an
* SPI it must be a separate number per vcpu. if (!pmu_irq_is_valid(vcpu->kvm, irq))
*/
if (irq < VGIC_NR_SGIS || irq >= vcpu->kvm->arch.vgic.nr_irqs ||
!irq_is_valid(vcpu->kvm, irq, irq < VGIC_NR_PRIVATE_IRQS))
return -EINVAL; return -EINVAL;
if (kvm_arm_pmu_irq_initialized(vcpu)) if (kvm_arm_pmu_irq_initialized(vcpu))
......
...@@ -171,7 +171,7 @@ static const struct vgic_ops vgic_v2_ops = { ...@@ -171,7 +171,7 @@ static const struct vgic_ops vgic_v2_ops = {
.enable = vgic_v2_enable, .enable = vgic_v2_enable,
}; };
static struct vgic_params vgic_v2_params; struct vgic_params __section(.hyp.text) vgic_v2_params;
static void vgic_cpu_init_lrs(void *params) static void vgic_cpu_init_lrs(void *params)
{ {
...@@ -201,6 +201,8 @@ int vgic_v2_probe(const struct gic_kvm_info *gic_kvm_info, ...@@ -201,6 +201,8 @@ int vgic_v2_probe(const struct gic_kvm_info *gic_kvm_info,
const struct resource *vctrl_res = &gic_kvm_info->vctrl; const struct resource *vctrl_res = &gic_kvm_info->vctrl;
const struct resource *vcpu_res = &gic_kvm_info->vcpu; const struct resource *vcpu_res = &gic_kvm_info->vcpu;
memset(vgic, 0, sizeof(*vgic));
if (!gic_kvm_info->maint_irq) { if (!gic_kvm_info->maint_irq) {
kvm_err("error getting vgic maintenance irq\n"); kvm_err("error getting vgic maintenance irq\n");
ret = -ENXIO; ret = -ENXIO;
......
...@@ -29,12 +29,6 @@ ...@@ -29,12 +29,6 @@
#include <asm/kvm_asm.h> #include <asm/kvm_asm.h>
#include <asm/kvm_mmu.h> #include <asm/kvm_mmu.h>
/* These are for GICv2 emulation only */
#define GICH_LR_VIRTUALID (0x3ffUL << 0)
#define GICH_LR_PHYSID_CPUID_SHIFT (10)
#define GICH_LR_PHYSID_CPUID (7UL << GICH_LR_PHYSID_CPUID_SHIFT)
#define ICH_LR_VIRTUALID_MASK (BIT_ULL(32) - 1)
static u32 ich_vtr_el2; static u32 ich_vtr_el2;
static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr) static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
...@@ -43,7 +37,7 @@ static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr) ...@@ -43,7 +37,7 @@ static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr]; u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr];
if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
lr_desc.irq = val & ICH_LR_VIRTUALID_MASK; lr_desc.irq = val & ICH_LR_VIRTUAL_ID_MASK;
else else
lr_desc.irq = val & GICH_LR_VIRTUALID; lr_desc.irq = val & GICH_LR_VIRTUALID;
......
...@@ -690,12 +690,11 @@ bool vgic_handle_cfg_reg(u32 *reg, struct kvm_exit_mmio *mmio, ...@@ -690,12 +690,11 @@ bool vgic_handle_cfg_reg(u32 *reg, struct kvm_exit_mmio *mmio,
*/ */
void vgic_unqueue_irqs(struct kvm_vcpu *vcpu) void vgic_unqueue_irqs(struct kvm_vcpu *vcpu)
{ {
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
u64 elrsr = vgic_get_elrsr(vcpu); u64 elrsr = vgic_get_elrsr(vcpu);
unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr); unsigned long *elrsr_ptr = u64_to_bitmask(&elrsr);
int i; int i;
for_each_clear_bit(i, elrsr_ptr, vgic_cpu->nr_lr) { for_each_clear_bit(i, elrsr_ptr, vgic->nr_lr) {
struct vgic_lr lr = vgic_get_lr(vcpu, i); struct vgic_lr lr = vgic_get_lr(vcpu, i);
/* /*
...@@ -820,7 +819,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu, ...@@ -820,7 +819,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
struct vgic_dist *dist = &vcpu->kvm->arch.vgic; struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
struct vgic_io_device *iodev = container_of(this, struct vgic_io_device *iodev = container_of(this,
struct vgic_io_device, dev); struct vgic_io_device, dev);
struct kvm_run *run = vcpu->run;
const struct vgic_io_range *range; const struct vgic_io_range *range;
struct kvm_exit_mmio mmio; struct kvm_exit_mmio mmio;
bool updated_state; bool updated_state;
...@@ -849,12 +847,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu, ...@@ -849,12 +847,6 @@ static int vgic_handle_mmio_access(struct kvm_vcpu *vcpu,
updated_state = false; updated_state = false;
} }
spin_unlock(&dist->lock); spin_unlock(&dist->lock);
run->mmio.is_write = is_write;
run->mmio.len = len;
run->mmio.phys_addr = addr;
memcpy(run->mmio.data, val, len);
kvm_handle_mmio_return(vcpu, run);
if (updated_state) if (updated_state)
vgic_kick_vcpus(vcpu->kvm); vgic_kick_vcpus(vcpu->kvm);
...@@ -1102,18 +1094,18 @@ static bool dist_active_irq(struct kvm_vcpu *vcpu) ...@@ -1102,18 +1094,18 @@ static bool dist_active_irq(struct kvm_vcpu *vcpu)
return test_bit(vcpu->vcpu_id, dist->irq_active_on_cpu); return test_bit(vcpu->vcpu_id, dist->irq_active_on_cpu);
} }
bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map) bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
{ {
int i; int i;
for (i = 0; i < vcpu->arch.vgic_cpu.nr_lr; i++) { for (i = 0; i < vgic->nr_lr; i++) {
struct vgic_lr vlr = vgic_get_lr(vcpu, i); struct vgic_lr vlr = vgic_get_lr(vcpu, i);
if (vlr.irq == map->virt_irq && vlr.state & LR_STATE_ACTIVE) if (vlr.irq == virt_irq && vlr.state & LR_STATE_ACTIVE)
return true; return true;
} }
return vgic_irq_is_active(vcpu, map->virt_irq); return vgic_irq_is_active(vcpu, virt_irq);
} }
/* /*
...@@ -1521,7 +1513,6 @@ static int vgic_validate_injection(struct kvm_vcpu *vcpu, int irq, int level) ...@@ -1521,7 +1513,6 @@ static int vgic_validate_injection(struct kvm_vcpu *vcpu, int irq, int level)
} }
static int vgic_update_irq_pending(struct kvm *kvm, int cpuid, static int vgic_update_irq_pending(struct kvm *kvm, int cpuid,
struct irq_phys_map *map,
unsigned int irq_num, bool level) unsigned int irq_num, bool level)
{ {
struct vgic_dist *dist = &kvm->arch.vgic; struct vgic_dist *dist = &kvm->arch.vgic;
...@@ -1660,14 +1651,14 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num, ...@@ -1660,14 +1651,14 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
if (map) if (map)
return -EINVAL; return -EINVAL;
return vgic_update_irq_pending(kvm, cpuid, NULL, irq_num, level); return vgic_update_irq_pending(kvm, cpuid, irq_num, level);
} }
/** /**
* kvm_vgic_inject_mapped_irq - Inject a physically mapped IRQ to the vgic * kvm_vgic_inject_mapped_irq - Inject a physically mapped IRQ to the vgic
* @kvm: The VM structure pointer * @kvm: The VM structure pointer
* @cpuid: The CPU for PPIs * @cpuid: The CPU for PPIs
* @map: Pointer to a irq_phys_map structure describing the mapping * @virt_irq: The virtual IRQ to be injected
* @level: Edge-triggered: true: to trigger the interrupt * @level: Edge-triggered: true: to trigger the interrupt
* false: to ignore the call * false: to ignore the call
* Level-sensitive true: raise the input signal * Level-sensitive true: raise the input signal
...@@ -1678,7 +1669,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num, ...@@ -1678,7 +1669,7 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
* being HIGH and 0 being LOW and all devices being active-HIGH. * being HIGH and 0 being LOW and all devices being active-HIGH.
*/ */
int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
struct irq_phys_map *map, bool level) unsigned int virt_irq, bool level)
{ {
int ret; int ret;
...@@ -1686,7 +1677,7 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid, ...@@ -1686,7 +1677,7 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
if (ret) if (ret)
return ret; return ret;
return vgic_update_irq_pending(kvm, cpuid, map, map->virt_irq, level); return vgic_update_irq_pending(kvm, cpuid, virt_irq, level);
} }
static irqreturn_t vgic_maintenance_handler(int irq, void *data) static irqreturn_t vgic_maintenance_handler(int irq, void *data)
...@@ -1712,43 +1703,28 @@ static struct list_head *vgic_get_irq_phys_map_list(struct kvm_vcpu *vcpu, ...@@ -1712,43 +1703,28 @@ static struct list_head *vgic_get_irq_phys_map_list(struct kvm_vcpu *vcpu,
/** /**
* kvm_vgic_map_phys_irq - map a virtual IRQ to a physical IRQ * kvm_vgic_map_phys_irq - map a virtual IRQ to a physical IRQ
* @vcpu: The VCPU pointer * @vcpu: The VCPU pointer
* @virt_irq: The virtual irq number * @virt_irq: The virtual IRQ number for the guest
* @irq: The Linux IRQ number * @phys_irq: The hardware IRQ number of the host
* *
* Establish a mapping between a guest visible irq (@virt_irq) and a * Establish a mapping between a guest visible irq (@virt_irq) and a
* Linux irq (@irq). On injection, @virt_irq will be associated with * hardware irq (@phys_irq). On injection, @virt_irq will be associated with
* the physical interrupt represented by @irq. This mapping can be * the physical interrupt represented by @phys_irq. This mapping can be
* established multiple times as long as the parameters are the same. * established multiple times as long as the parameters are the same.
* *
* Returns a valid pointer on success, and an error pointer otherwise * Returns 0 on success or an error value otherwise.
*/ */
struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, int virt_irq, int phys_irq)
int virt_irq, int irq)
{ {
struct vgic_dist *dist = &vcpu->kvm->arch.vgic; struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
struct list_head *root = vgic_get_irq_phys_map_list(vcpu, virt_irq); struct list_head *root = vgic_get_irq_phys_map_list(vcpu, virt_irq);
struct irq_phys_map *map; struct irq_phys_map *map;
struct irq_phys_map_entry *entry; struct irq_phys_map_entry *entry;
struct irq_desc *desc; int ret = 0;
struct irq_data *data;
int phys_irq;
desc = irq_to_desc(irq);
if (!desc) {
kvm_err("%s: no interrupt descriptor\n", __func__);
return ERR_PTR(-EINVAL);
}
data = irq_desc_get_irq_data(desc);
while (data->parent_data)
data = data->parent_data;
phys_irq = data->hwirq;
/* Create a new mapping */ /* Create a new mapping */
entry = kzalloc(sizeof(*entry), GFP_KERNEL); entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) if (!entry)
return ERR_PTR(-ENOMEM); return -ENOMEM;
spin_lock(&dist->irq_phys_map_lock); spin_lock(&dist->irq_phys_map_lock);
...@@ -1756,9 +1732,8 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, ...@@ -1756,9 +1732,8 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
map = vgic_irq_map_search(vcpu, virt_irq); map = vgic_irq_map_search(vcpu, virt_irq);
if (map) { if (map) {
/* Make sure this mapping matches */ /* Make sure this mapping matches */
if (map->phys_irq != phys_irq || if (map->phys_irq != phys_irq)
map->irq != irq) ret = -EINVAL;
map = ERR_PTR(-EINVAL);
/* Found an existing, valid mapping */ /* Found an existing, valid mapping */
goto out; goto out;
...@@ -1767,7 +1742,6 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, ...@@ -1767,7 +1742,6 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
map = &entry->map; map = &entry->map;
map->virt_irq = virt_irq; map->virt_irq = virt_irq;
map->phys_irq = phys_irq; map->phys_irq = phys_irq;
map->irq = irq;
list_add_tail_rcu(&entry->entry, root); list_add_tail_rcu(&entry->entry, root);
...@@ -1775,9 +1749,9 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, ...@@ -1775,9 +1749,9 @@ struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
spin_unlock(&dist->irq_phys_map_lock); spin_unlock(&dist->irq_phys_map_lock);
/* If we've found a hit in the existing list, free the useless /* If we've found a hit in the existing list, free the useless
* entry */ * entry */
if (IS_ERR(map) || map != &entry->map) if (ret || map != &entry->map)
kfree(entry); kfree(entry);
return map; return ret;
} }
static struct irq_phys_map *vgic_irq_map_search(struct kvm_vcpu *vcpu, static struct irq_phys_map *vgic_irq_map_search(struct kvm_vcpu *vcpu,
...@@ -1813,25 +1787,22 @@ static void vgic_free_phys_irq_map_rcu(struct rcu_head *rcu) ...@@ -1813,25 +1787,22 @@ static void vgic_free_phys_irq_map_rcu(struct rcu_head *rcu)
/** /**
* kvm_vgic_unmap_phys_irq - Remove a virtual to physical IRQ mapping * kvm_vgic_unmap_phys_irq - Remove a virtual to physical IRQ mapping
* @vcpu: The VCPU pointer * @vcpu: The VCPU pointer
* @map: The pointer to a mapping obtained through kvm_vgic_map_phys_irq * @virt_irq: The virtual IRQ number to be unmapped
* *
* Remove an existing mapping between virtual and physical interrupts. * Remove an existing mapping between virtual and physical interrupts.
*/ */
int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map) int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int virt_irq)
{ {
struct vgic_dist *dist = &vcpu->kvm->arch.vgic; struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
struct irq_phys_map_entry *entry; struct irq_phys_map_entry *entry;
struct list_head *root; struct list_head *root;
if (!map) root = vgic_get_irq_phys_map_list(vcpu, virt_irq);
return -EINVAL;
root = vgic_get_irq_phys_map_list(vcpu, map->virt_irq);
spin_lock(&dist->irq_phys_map_lock); spin_lock(&dist->irq_phys_map_lock);
list_for_each_entry(entry, root, entry) { list_for_each_entry(entry, root, entry) {
if (&entry->map == map) { if (entry->map.virt_irq == virt_irq) {
list_del_rcu(&entry->entry); list_del_rcu(&entry->entry);
call_rcu(&entry->rcu, vgic_free_phys_irq_map_rcu); call_rcu(&entry->rcu, vgic_free_phys_irq_map_rcu);
break; break;
...@@ -1887,13 +1858,6 @@ static int vgic_vcpu_init_maps(struct kvm_vcpu *vcpu, int nr_irqs) ...@@ -1887,13 +1858,6 @@ static int vgic_vcpu_init_maps(struct kvm_vcpu *vcpu, int nr_irqs)
return -ENOMEM; return -ENOMEM;
} }
/*
* Store the number of LRs per vcpu, so we don't have to go
* all the way to the distributor structure to find out. Only
* assembly code should use this one.
*/
vgic_cpu->nr_lr = vgic->nr_lr;
return 0; return 0;
} }
......
This diff is collapsed.
/*
* Copyright (C) 2015, 2016 ARM Ltd.
*
* 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.h>
#include <linux/kvm_host.h>
#include <trace/events/kvm.h>
int kvm_irq_map_gsi(struct kvm *kvm,
struct kvm_kernel_irq_routing_entry *entries,
int gsi)
{
return 0;
}
int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned int irqchip,
unsigned int pin)
{
return pin;
}
int kvm_set_irq(struct kvm *kvm, int irq_source_id,
u32 irq, int level, bool line_status)
{
unsigned int spi = irq + VGIC_NR_PRIVATE_IRQS;
trace_kvm_set_irq(irq, level, irq_source_id);
BUG_ON(!vgic_initialized(kvm));
return kvm_vgic_inject_irq(kvm, 0, spi, level);
}
/* MSI not implemented yet */
int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int irq_source_id,
int level, bool line_status)
{
return 0;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment