提交 7f22b45d 编写于 作者: P Paolo Bonzini

Merge tag 'kvm-s390-next-20150331' of...

Merge tag 'kvm-s390-next-20150331' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into HEAD

Features and fixes for 4.1 (kvm/next)

1. Assorted changes
1.1 allow more feature bits for the guest
1.2 Store breaking event address on program interrupts

2. Interrupt handling rework
2.1 Fix copy_to_user while holding a spinlock (cc stable)
2.2 Rework floating interrupts to follow the priorities
2.3 Allow to inject all local interrupts via new ioctl
2.4 allow to get/set the full local irq state, e.g. for migration
    and introspection
...@@ -2861,6 +2861,123 @@ single frame starting at start_gfn for count frames. ...@@ -2861,6 +2861,123 @@ single frame starting at start_gfn for count frames.
Note: If any architecturally invalid key value is found in the given data then Note: If any architecturally invalid key value is found in the given data then
the ioctl will return -EINVAL. the ioctl will return -EINVAL.
4.92 KVM_S390_IRQ
Capability: KVM_CAP_S390_INJECT_IRQ
Architectures: s390
Type: vcpu ioctl
Parameters: struct kvm_s390_irq (in)
Returns: 0 on success, -1 on error
Errors:
EINVAL: interrupt type is invalid
type is KVM_S390_SIGP_STOP and flag parameter is invalid value
type is KVM_S390_INT_EXTERNAL_CALL and code is bigger
than the maximum of VCPUs
EBUSY: type is KVM_S390_SIGP_SET_PREFIX and vcpu is not stopped
type is KVM_S390_SIGP_STOP and a stop irq is already pending
type is KVM_S390_INT_EXTERNAL_CALL and an external call interrupt
is already pending
Allows to inject an interrupt to the guest.
Using struct kvm_s390_irq as a parameter allows
to inject additional payload which is not
possible via KVM_S390_INTERRUPT.
Interrupt parameters are passed via kvm_s390_irq:
struct kvm_s390_irq {
__u64 type;
union {
struct kvm_s390_io_info io;
struct kvm_s390_ext_info ext;
struct kvm_s390_pgm_info pgm;
struct kvm_s390_emerg_info emerg;
struct kvm_s390_extcall_info extcall;
struct kvm_s390_prefix_info prefix;
struct kvm_s390_stop_info stop;
struct kvm_s390_mchk_info mchk;
char reserved[64];
} u;
};
type can be one of the following:
KVM_S390_SIGP_STOP - sigp stop; parameter in .stop
KVM_S390_PROGRAM_INT - program check; parameters in .pgm
KVM_S390_SIGP_SET_PREFIX - sigp set prefix; parameters in .prefix
KVM_S390_RESTART - restart; no parameters
KVM_S390_INT_CLOCK_COMP - clock comparator interrupt; no parameters
KVM_S390_INT_CPU_TIMER - CPU timer interrupt; no parameters
KVM_S390_INT_EMERGENCY - sigp emergency; parameters in .emerg
KVM_S390_INT_EXTERNAL_CALL - sigp external call; parameters in .extcall
KVM_S390_MCHK - machine check interrupt; parameters in .mchk
Note that the vcpu ioctl is asynchronous to vcpu execution.
4.94 KVM_S390_GET_IRQ_STATE
Capability: KVM_CAP_S390_IRQ_STATE
Architectures: s390
Type: vcpu ioctl
Parameters: struct kvm_s390_irq_state (out)
Returns: >= number of bytes copied into buffer,
-EINVAL if buffer size is 0,
-ENOBUFS if buffer size is too small to fit all pending interrupts,
-EFAULT if the buffer address was invalid
This ioctl allows userspace to retrieve the complete state of all currently
pending interrupts in a single buffer. Use cases include migration
and introspection. The parameter structure contains the address of a
userspace buffer and its length:
struct kvm_s390_irq_state {
__u64 buf;
__u32 flags;
__u32 len;
__u32 reserved[4];
};
Userspace passes in the above struct and for each pending interrupt a
struct kvm_s390_irq is copied to the provided buffer.
If -ENOBUFS is returned the buffer provided was too small and userspace
may retry with a bigger buffer.
4.95 KVM_S390_SET_IRQ_STATE
Capability: KVM_CAP_S390_IRQ_STATE
Architectures: s390
Type: vcpu ioctl
Parameters: struct kvm_s390_irq_state (in)
Returns: 0 on success,
-EFAULT if the buffer address was invalid,
-EINVAL for an invalid buffer length (see below),
-EBUSY if there were already interrupts pending,
errors occurring when actually injecting the
interrupt. See KVM_S390_IRQ.
This ioctl allows userspace to set the complete state of all cpu-local
interrupts currently pending for the vcpu. It is intended for restoring
interrupt state after a migration. The input parameter is a userspace buffer
containing a struct kvm_s390_irq_state:
struct kvm_s390_irq_state {
__u64 buf;
__u32 len;
__u32 pad;
};
The userspace memory referenced by buf contains a struct kvm_s390_irq
for each interrupt to be injected into the guest.
If one of the interrupts could not be injected for some reason the
ioctl aborts.
len must be a multiple of sizeof(struct kvm_s390_irq). It must be > 0
and it must not exceed (max_vcpus + 32) * sizeof(struct kvm_s390_irq),
which is the maximum number of possibly pending cpu-local interrupts.
5. The kvm_run structure 5. The kvm_run structure
------------------------ ------------------------
......
...@@ -27,6 +27,9 @@ Groups: ...@@ -27,6 +27,9 @@ Groups:
Copies all floating interrupts into a buffer provided by userspace. Copies all floating interrupts into a buffer provided by userspace.
When the buffer is too small it returns -ENOMEM, which is the indication When the buffer is too small it returns -ENOMEM, which is the indication
for userspace to try again with a bigger buffer. for userspace to try again with a bigger buffer.
-ENOBUFS is returned when the allocation of a kernelspace buffer has
failed.
-EFAULT is returned when copying data to userspace failed.
All interrupts remain pending, i.e. are not deleted from the list of All interrupts remain pending, i.e. are not deleted from the list of
currently pending interrupts. currently pending interrupts.
attr->addr contains the userspace address of the buffer into which all attr->addr contains the userspace address of the buffer into which all
......
...@@ -344,6 +344,11 @@ enum irq_types { ...@@ -344,6 +344,11 @@ enum irq_types {
IRQ_PEND_COUNT IRQ_PEND_COUNT
}; };
/* We have 2M for virtio device descriptor pages. Smallest amount of
* memory per page is 24 bytes (1 queue), so (2048*1024) / 24 = 87381
*/
#define KVM_S390_MAX_VIRTIO_IRQS 87381
/* /*
* Repressible (non-floating) machine check interrupts * Repressible (non-floating) machine check interrupts
* subclass bits in MCIC * subclass bits in MCIC
...@@ -421,13 +426,32 @@ struct kvm_s390_local_interrupt { ...@@ -421,13 +426,32 @@ struct kvm_s390_local_interrupt {
unsigned long pending_irqs; unsigned long pending_irqs;
}; };
#define FIRQ_LIST_IO_ISC_0 0
#define FIRQ_LIST_IO_ISC_1 1
#define FIRQ_LIST_IO_ISC_2 2
#define FIRQ_LIST_IO_ISC_3 3
#define FIRQ_LIST_IO_ISC_4 4
#define FIRQ_LIST_IO_ISC_5 5
#define FIRQ_LIST_IO_ISC_6 6
#define FIRQ_LIST_IO_ISC_7 7
#define FIRQ_LIST_PFAULT 8
#define FIRQ_LIST_VIRTIO 9
#define FIRQ_LIST_COUNT 10
#define FIRQ_CNTR_IO 0
#define FIRQ_CNTR_SERVICE 1
#define FIRQ_CNTR_VIRTIO 2
#define FIRQ_CNTR_PFAULT 3
#define FIRQ_MAX_COUNT 4
struct kvm_s390_float_interrupt { struct kvm_s390_float_interrupt {
unsigned long pending_irqs;
spinlock_t lock; spinlock_t lock;
struct list_head list; struct list_head lists[FIRQ_LIST_COUNT];
atomic_t active; int counters[FIRQ_MAX_COUNT];
struct kvm_s390_mchk_info mchk;
struct kvm_s390_ext_info srv_signal;
int next_rr_cpu; int next_rr_cpu;
unsigned long idle_mask[BITS_TO_LONGS(KVM_MAX_VCPUS)]; unsigned long idle_mask[BITS_TO_LONGS(KVM_MAX_VCPUS)];
unsigned int irq_count;
}; };
struct kvm_hw_wp_info_arch { struct kvm_hw_wp_info_arch {
......
此差异已折叠。
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/nmi.h> #include <asm/nmi.h>
#include <asm/switch_to.h> #include <asm/switch_to.h>
#include <asm/isc.h>
#include <asm/sclp.h> #include <asm/sclp.h>
#include "kvm-s390.h" #include "kvm-s390.h"
#include "gaccess.h" #include "gaccess.h"
...@@ -40,6 +41,9 @@ ...@@ -40,6 +41,9 @@
#include "trace-s390.h" #include "trace-s390.h"
#define MEM_OP_MAX_SIZE 65536 /* Maximum transfer size for KVM_S390_MEM_OP */ #define MEM_OP_MAX_SIZE 65536 /* Maximum transfer size for KVM_S390_MEM_OP */
#define LOCAL_IRQS 32
#define VCPU_IRQS_MAX_BUF (sizeof(struct kvm_s390_irq) * \
(KVM_MAX_VCPUS + LOCAL_IRQS))
#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
...@@ -105,8 +109,8 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { ...@@ -105,8 +109,8 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
/* upper facilities limit for kvm */ /* upper facilities limit for kvm */
unsigned long kvm_s390_fac_list_mask[] = { unsigned long kvm_s390_fac_list_mask[] = {
0xff82fffbf4fc2000UL, 0xffe6fffbfcfdfc40UL,
0x005c000000000000UL, 0x205c800000000000UL,
}; };
unsigned long kvm_s390_fac_list_mask_size(void) unsigned long kvm_s390_fac_list_mask_size(void)
...@@ -176,9 +180,11 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) ...@@ -176,9 +180,11 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_S390_IRQCHIP: case KVM_CAP_S390_IRQCHIP:
case KVM_CAP_VM_ATTRIBUTES: case KVM_CAP_VM_ATTRIBUTES:
case KVM_CAP_MP_STATE: case KVM_CAP_MP_STATE:
case KVM_CAP_S390_INJECT_IRQ:
case KVM_CAP_S390_USER_SIGP: case KVM_CAP_S390_USER_SIGP:
case KVM_CAP_S390_USER_STSI: case KVM_CAP_S390_USER_STSI:
case KVM_CAP_S390_SKEYS: case KVM_CAP_S390_SKEYS:
case KVM_CAP_S390_IRQ_STATE:
r = 1; r = 1;
break; break;
case KVM_CAP_S390_MEM_OP: case KVM_CAP_S390_MEM_OP:
...@@ -1069,7 +1075,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) ...@@ -1069,7 +1075,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
goto out_err; goto out_err;
spin_lock_init(&kvm->arch.float_int.lock); spin_lock_init(&kvm->arch.float_int.lock);
INIT_LIST_HEAD(&kvm->arch.float_int.list); for (i = 0; i < FIRQ_LIST_COUNT; i++)
INIT_LIST_HEAD(&kvm->arch.float_int.lists[i]);
init_waitqueue_head(&kvm->arch.ipte_wq); init_waitqueue_head(&kvm->arch.ipte_wq);
mutex_init(&kvm->arch.ipte_mutex); mutex_init(&kvm->arch.ipte_mutex);
...@@ -2389,6 +2396,15 @@ long kvm_arch_vcpu_ioctl(struct file *filp, ...@@ -2389,6 +2396,15 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
long r; long r;
switch (ioctl) { switch (ioctl) {
case KVM_S390_IRQ: {
struct kvm_s390_irq s390irq;
r = -EFAULT;
if (copy_from_user(&s390irq, argp, sizeof(s390irq)))
break;
r = kvm_s390_inject_vcpu(vcpu, &s390irq);
break;
}
case KVM_S390_INTERRUPT: { case KVM_S390_INTERRUPT: {
struct kvm_s390_interrupt s390int; struct kvm_s390_interrupt s390int;
struct kvm_s390_irq s390irq; struct kvm_s390_irq s390irq;
...@@ -2488,6 +2504,38 @@ long kvm_arch_vcpu_ioctl(struct file *filp, ...@@ -2488,6 +2504,38 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = -EFAULT; r = -EFAULT;
break; break;
} }
case KVM_S390_SET_IRQ_STATE: {
struct kvm_s390_irq_state irq_state;
r = -EFAULT;
if (copy_from_user(&irq_state, argp, sizeof(irq_state)))
break;
if (irq_state.len > VCPU_IRQS_MAX_BUF ||
irq_state.len == 0 ||
irq_state.len % sizeof(struct kvm_s390_irq) > 0) {
r = -EINVAL;
break;
}
r = kvm_s390_set_irq_state(vcpu,
(void __user *) irq_state.buf,
irq_state.len);
break;
}
case KVM_S390_GET_IRQ_STATE: {
struct kvm_s390_irq_state irq_state;
r = -EFAULT;
if (copy_from_user(&irq_state, argp, sizeof(irq_state)))
break;
if (irq_state.len == 0) {
r = -EINVAL;
break;
}
r = kvm_s390_get_irq_state(vcpu,
(__u8 __user *) irq_state.buf,
irq_state.len);
break;
}
default: default:
r = -ENOTTY; r = -ENOTTY;
} }
......
...@@ -178,7 +178,7 @@ int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, ...@@ -178,7 +178,7 @@ int __must_check kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
struct kvm_s390_irq *irq); struct kvm_s390_irq *irq);
int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm, struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm,
u64 cr6, u64 schid); u64 isc_mask, u32 schid);
int kvm_s390_reinject_io_int(struct kvm *kvm, int kvm_s390_reinject_io_int(struct kvm *kvm,
struct kvm_s390_interrupt_info *inti); struct kvm_s390_interrupt_info *inti);
int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked); int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked);
...@@ -272,6 +272,10 @@ int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu); ...@@ -272,6 +272,10 @@ int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu);
extern struct kvm_device_ops kvm_flic_ops; extern struct kvm_device_ops kvm_flic_ops;
int kvm_s390_is_stop_irq_pending(struct kvm_vcpu *vcpu); int kvm_s390_is_stop_irq_pending(struct kvm_vcpu *vcpu);
void kvm_s390_clear_stop_irq(struct kvm_vcpu *vcpu); void kvm_s390_clear_stop_irq(struct kvm_vcpu *vcpu);
int kvm_s390_set_irq_state(struct kvm_vcpu *vcpu,
void __user *buf, int len);
int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu,
__u8 __user *buf, int len);
/* implemented in guestdbg.c */ /* implemented in guestdbg.c */
void kvm_s390_backup_guest_per_regs(struct kvm_vcpu *vcpu); void kvm_s390_backup_guest_per_regs(struct kvm_vcpu *vcpu);
......
...@@ -294,10 +294,13 @@ static int handle_tpi(struct kvm_vcpu *vcpu) ...@@ -294,10 +294,13 @@ static int handle_tpi(struct kvm_vcpu *vcpu)
static int handle_tsch(struct kvm_vcpu *vcpu) static int handle_tsch(struct kvm_vcpu *vcpu)
{ {
struct kvm_s390_interrupt_info *inti; struct kvm_s390_interrupt_info *inti = NULL;
const u64 isc_mask = 0xffUL << 24; /* all iscs set */
inti = kvm_s390_get_io_int(vcpu->kvm, 0, /* a valid schid has at least one bit set */
vcpu->run->s.regs.gprs[1]); if (vcpu->run->s.regs.gprs[1])
inti = kvm_s390_get_io_int(vcpu->kvm, isc_mask,
vcpu->run->s.regs.gprs[1]);
/* /*
* Prepare exit to userspace. * Prepare exit to userspace.
......
...@@ -558,6 +558,13 @@ struct kvm_s390_irq { ...@@ -558,6 +558,13 @@ struct kvm_s390_irq {
} u; } u;
}; };
struct kvm_s390_irq_state {
__u64 buf;
__u32 flags;
__u32 len;
__u32 reserved[4];
};
/* for KVM_SET_GUEST_DEBUG */ /* for KVM_SET_GUEST_DEBUG */
#define KVM_GUESTDBG_ENABLE 0x00000001 #define KVM_GUESTDBG_ENABLE 0x00000001
...@@ -804,6 +811,8 @@ struct kvm_ppc_smmu_info { ...@@ -804,6 +811,8 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_S390_SKEYS 110 #define KVM_CAP_S390_SKEYS 110
#define KVM_CAP_MIPS_FPU 111 #define KVM_CAP_MIPS_FPU 111
#define KVM_CAP_MIPS_MSA 112 #define KVM_CAP_MIPS_MSA 112
#define KVM_CAP_S390_INJECT_IRQ 113
#define KVM_CAP_S390_IRQ_STATE 114
#ifdef KVM_CAP_IRQ_ROUTING #ifdef KVM_CAP_IRQ_ROUTING
...@@ -1184,6 +1193,11 @@ struct kvm_s390_ucas_mapping { ...@@ -1184,6 +1193,11 @@ struct kvm_s390_ucas_mapping {
/* Available with KVM_CAP_S390_SKEYS */ /* Available with KVM_CAP_S390_SKEYS */
#define KVM_S390_GET_SKEYS _IOW(KVMIO, 0xb2, struct kvm_s390_skeys) #define KVM_S390_GET_SKEYS _IOW(KVMIO, 0xb2, struct kvm_s390_skeys)
#define KVM_S390_SET_SKEYS _IOW(KVMIO, 0xb3, struct kvm_s390_skeys) #define KVM_S390_SET_SKEYS _IOW(KVMIO, 0xb3, struct kvm_s390_skeys)
/* Available with KVM_CAP_S390_INJECT_IRQ */
#define KVM_S390_IRQ _IOW(KVMIO, 0xb4, struct kvm_s390_irq)
/* Available with KVM_CAP_S390_IRQ_STATE */
#define KVM_S390_SET_IRQ_STATE _IOW(KVMIO, 0xb5, struct kvm_s390_irq_state)
#define KVM_S390_GET_IRQ_STATE _IOW(KVMIO, 0xb6, struct kvm_s390_irq_state)
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
#define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1) #define KVM_DEV_ASSIGN_PCI_2_3 (1 << 1)
......
...@@ -2113,7 +2113,7 @@ static long kvm_vcpu_ioctl(struct file *filp, ...@@ -2113,7 +2113,7 @@ static long kvm_vcpu_ioctl(struct file *filp,
* Special cases: vcpu ioctls that are asynchronous to vcpu execution, * Special cases: vcpu ioctls that are asynchronous to vcpu execution,
* so vcpu_load() would break it. * so vcpu_load() would break it.
*/ */
if (ioctl == KVM_S390_INTERRUPT || ioctl == KVM_INTERRUPT) if (ioctl == KVM_S390_INTERRUPT || ioctl == KVM_S390_IRQ || ioctl == KVM_INTERRUPT)
return kvm_arch_vcpu_ioctl(filp, ioctl, arg); return kvm_arch_vcpu_ioctl(filp, ioctl, arg);
#endif #endif
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册