This patch series adds support for user space save/restore of the VGIC state. Instead of expanding the ONE_REG interface, which works on VCPUs, we first introduce support for the new KVM device control API and the VGIC. Now, instead of calling KVM_CREATE_IRQCHIP, user space can call KVM_CREATE_DEVICE and perform operations on the device fd, such as KVM_SET_DEVICE_ATTR to set a device attribute.
We leverage the KVM_{SET/GET}_DEVICE_ATTR API to export the state of the VGIC to user space. Instead of coming up with our own custom format for exporting the VGIC state, we simply export all the state visible to an emulated guest, which must contain the full GIC state to provide save/restore of the GIC state for power management purposes. This further provides the benefit of being able to re-use the MMIO emulation code for the distributor for save/restore.
However, the need to save/restore cpu-specific state demands that user space can save/restore state accessible through the CPU interface, and we therefore add an emulation interface for the CPU-specific interface.
This is considered a first attempt, and I am not married to the device control API. If there are good technical arguments to take another approach, I am of course willing to discuss this. However, my attempts with the ONE_REG interface did not look very nice.
[ WARINING: The patch set core functionality is completely untested; the basic KVM system has been briefly tested on TC2 and it doesn't seem like I've broken existing functionality. ]
I wanted to get this out early to get feedback on the overall API and idea, and I'm writing some user QEMU for the user space side to test the new functionality meanwhile.
Patches are against kvm-arm-next and also available here: git://git.linaro.org/people/cdall/linux-kvm-arm.git vgic-migrate
Christoffer Dall (7): KVM: arm-vgic: Support KVM_CREATE_DEVICE for VGIC KVM: arm-vgic: Set base addr through device API irqchip: arm-gic: Define additional MMIO offsets and masks KVM: arm-vgic: Make vgic mmio functions more generic KVM: arm-vgic: Add vgic reg access from dev attr KVM: arm-vgic: Add GICD_SPENDSGIR and GICD_CPENDSGIR handlers KVM: arm-vgic: Support CPU interface reg access
Documentation/virtual/kvm/api.txt | 5 +- Documentation/virtual/kvm/devices/arm-vgic.txt | 52 +++ arch/arm/include/uapi/asm/kvm.h | 8 + arch/arm/kvm/arm.c | 3 +- include/kvm/arm_vgic.h | 2 +- include/linux/irqchip/arm-gic.h | 14 + include/linux/kvm_host.h | 1 + include/uapi/linux/kvm.h | 1 + virt/kvm/arm/vgic.c | 452 +++++++++++++++++++++++- virt/kvm/kvm_main.c | 4 + 10 files changed, 522 insertions(+), 20 deletions(-) create mode 100644 Documentation/virtual/kvm/devices/arm-vgic.txt
Support creating the ARM VGIC device through the KVM_CREATE_DEVICE ioctl, which can then later be leveraged to use the KVM_{GET/SET}_DEVICE_ATTR, which is useful both for setting addresses in a more generic API than the ARM-specific one and is useful for save/restore of VGIC state.
Adds KVM_CAP_DEVICE_CTRL to ARM capabilities.
Signed-off-by: Christoffer Dall christoffer.dall@linaro.org --- Documentation/virtual/kvm/devices/arm-vgic.txt | 10 +++++++ arch/arm/include/uapi/asm/kvm.h | 8 ++++++ arch/arm/kvm/arm.c | 1 + include/linux/kvm_host.h | 1 + include/uapi/linux/kvm.h | 1 + virt/kvm/arm/vgic.c | 34 ++++++++++++++++++++++++ virt/kvm/kvm_main.c | 4 +++ 7 files changed, 59 insertions(+) create mode 100644 Documentation/virtual/kvm/devices/arm-vgic.txt
diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt new file mode 100644 index 0000000..25fd2d9 --- /dev/null +++ b/Documentation/virtual/kvm/devices/arm-vgic.txt @@ -0,0 +1,10 @@ +MPIC interrupt controller +========================= + +Device types supported: + KVM_DEV_TYPE_ARM_VGIC ARM Generic Interrupt Controller v2.0 + +Only one VGIC instance may be instantiated through either this API or the +legacy KVM_CREATE_IRQCHIP api. The created VGIC will act as the VM interrupt +controller, requiring emulated user-space devices to inject interrupts to the +VGIC instead of directly to CPUs. diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h index c1ee007..587f1ae 100644 --- a/arch/arm/include/uapi/asm/kvm.h +++ b/arch/arm/include/uapi/asm/kvm.h @@ -142,6 +142,14 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_VFP_FPINST 0x1009 #define KVM_REG_ARM_VFP_FPINST2 0x100A
+/* Device Control API: ARM VGIC */ +#define KVM_DEV_ARM_VGIC_GRP_ADDR 0 +#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 +#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2 +#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32 +#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT) +#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0 +#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
/* KVM_IRQ_LINE irq field index values */ #define KVM_ARM_IRQ_TYPE_SHIFT 24 diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 741f66a..b8e3b6e 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -187,6 +187,7 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_IRQCHIP: r = vgic_present; break; + case KVM_CAP_DEVICE_CTRL: case KVM_CAP_USER_MEMORY: case KVM_CAP_SYNC_MMU: case KVM_CAP_DESTROY_MEMORY_REGION_WORKS: diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index d9a3c30..e2d6556 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1086,6 +1086,7 @@ struct kvm_device *kvm_device_from_filp(struct file *filp);
extern struct kvm_device_ops kvm_mpic_ops; extern struct kvm_device_ops kvm_xics_ops; +extern struct kvm_device_ops kvm_arm_vgic_ops;
#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index a5c86fc..4f2a4ab 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -839,6 +839,7 @@ struct kvm_device_attr { #define KVM_DEV_TYPE_FSL_MPIC_20 1 #define KVM_DEV_TYPE_FSL_MPIC_42 2 #define KVM_DEV_TYPE_XICS 3 +#define KVM_DEV_TYPE_ARM_VGIC 4
/* * ioctls for VM fds diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 17c5ac7..b3dcd66 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -1497,3 +1497,37 @@ int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr) mutex_unlock(&kvm->lock); return r; } + +static int vgic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) +{ + return -ENXIO; +} + +static int vgic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) +{ + return -ENXIO; +} + +static int vgic_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr) +{ + return -ENXIO; +} + +static void vgic_destroy(struct kvm_device *dev) +{ + kfree(dev); +} + +static int vgic_create(struct kvm_device *dev, u32 type) +{ + return kvm_vgic_create(dev->kvm); +} + +struct kvm_device_ops kvm_arm_vgic_ops = { + .name = "kvm-arm-vgic", + .create = vgic_create, + .destroy = vgic_destroy, + .set_attr = vgic_set_attr, + .get_attr = vgic_get_attr, + .has_attr = vgic_has_attr, +}; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index b547a1c..774e77c 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2282,6 +2282,10 @@ static int kvm_ioctl_create_device(struct kvm *kvm, ops = &kvm_xics_ops; break; #endif +#ifdef CONFIG_KVM_ARM_VGIC + case KVM_DEV_TYPE_ARM_VGIC: + ops = &kvm_arm_vgic_ops; +#endif default: return -ENODEV; }
Am 11.06.2013 um 06:51 schrieb Christoffer Dall christoffer.dall@linaro.org:
Support creating the ARM VGIC device through the KVM_CREATE_DEVICE ioctl, which can then later be leveraged to use the KVM_{GET/SET}_DEVICE_ATTR, which is useful both for setting addresses in a more generic API than the ARM-specific one and is useful for save/restore of VGIC state.
Adds KVM_CAP_DEVICE_CTRL to ARM capabilities.
Signed-off-by: Christoffer Dall christoffer.dall@linaro.org
Documentation/virtual/kvm/devices/arm-vgic.txt | 10 +++++++ arch/arm/include/uapi/asm/kvm.h | 8 ++++++ arch/arm/kvm/arm.c | 1 + include/linux/kvm_host.h | 1 + include/uapi/linux/kvm.h | 1 + virt/kvm/arm/vgic.c | 34 ++++++++++++++++++++++++ virt/kvm/kvm_main.c | 4 +++ 7 files changed, 59 insertions(+) create mode 100644 Documentation/virtual/kvm/devices/arm-vgic.txt
diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt new file mode 100644 index 0000000..25fd2d9 --- /dev/null +++ b/Documentation/virtual/kvm/devices/arm-vgic.txt @@ -0,0 +1,10 @@ +MPIC interrupt controller
MPIC?
+=========================
+Device types supported:
- KVM_DEV_TYPE_ARM_VGIC ARM Generic Interrupt Controller v2.0
+Only one VGIC instance may be instantiated through either this API or the +legacy KVM_CREATE_IRQCHIP api. The created VGIC will act as the VM interrupt +controller, requiring emulated user-space devices to inject interrupts to the +VGIC instead of directly to CPUs. diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h index c1ee007..587f1ae 100644 --- a/arch/arm/include/uapi/asm/kvm.h +++ b/arch/arm/include/uapi/asm/kvm.h @@ -142,6 +142,14 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_VFP_FPINST 0x1009 #define KVM_REG_ARM_VFP_FPINST2 0x100A
+/* Device Control API: ARM VGIC */ +#define KVM_DEV_ARM_VGIC_GRP_ADDR 0 +#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 +#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2 +#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32 +#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT) +#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0 +#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
Could you please describe the groups in the documentation too?
/* KVM_IRQ_LINE irq field index values */ #define KVM_ARM_IRQ_TYPE_SHIFT 24 diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 741f66a..b8e3b6e 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -187,6 +187,7 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_IRQCHIP: r = vgic_present; break;
- case KVM_CAP_DEVICE_CTRL: case KVM_CAP_USER_MEMORY: case KVM_CAP_SYNC_MMU: case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index d9a3c30..e2d6556 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1086,6 +1086,7 @@ struct kvm_device *kvm_device_from_filp(struct file *filp);
extern struct kvm_device_ops kvm_mpic_ops; extern struct kvm_device_ops kvm_xics_ops; +extern struct kvm_device_ops kvm_arm_vgic_ops;
#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index a5c86fc..4f2a4ab 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -839,6 +839,7 @@ struct kvm_device_attr { #define KVM_DEV_TYPE_FSL_MPIC_20 1 #define KVM_DEV_TYPE_FSL_MPIC_42 2 #define KVM_DEV_TYPE_XICS 3 +#define KVM_DEV_TYPE_ARM_VGIC 4
Should this be versioned? Gicv2 is different from v3, no?
Alex
/*
- ioctls for VM fds
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 17c5ac7..b3dcd66 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -1497,3 +1497,37 @@ int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr) mutex_unlock(&kvm->lock); return r; }
+static int vgic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) +{
- return -ENXIO;
+}
+static int vgic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) +{
- return -ENXIO;
+}
+static int vgic_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr) +{
- return -ENXIO;
+}
+static void vgic_destroy(struct kvm_device *dev) +{
- kfree(dev);
+}
+static int vgic_create(struct kvm_device *dev, u32 type) +{
- return kvm_vgic_create(dev->kvm);
+}
+struct kvm_device_ops kvm_arm_vgic_ops = {
- .name = "kvm-arm-vgic",
- .create = vgic_create,
- .destroy = vgic_destroy,
- .set_attr = vgic_set_attr,
- .get_attr = vgic_get_attr,
- .has_attr = vgic_has_attr,
+}; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index b547a1c..774e77c 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2282,6 +2282,10 @@ static int kvm_ioctl_create_device(struct kvm *kvm, ops = &kvm_xics_ops; break; #endif +#ifdef CONFIG_KVM_ARM_VGIC
- case KVM_DEV_TYPE_ARM_VGIC:
ops = &kvm_arm_vgic_ops;
+#endif default: return -ENODEV; } -- 1.7.9.5
kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm
On Tue, Jun 18, 2013 at 03:21:38PM +0200, Alexander Graf wrote:
Am 11.06.2013 um 06:51 schrieb Christoffer Dall christoffer.dall@linaro.org:
Support creating the ARM VGIC device through the KVM_CREATE_DEVICE ioctl, which can then later be leveraged to use the KVM_{GET/SET}_DEVICE_ATTR, which is useful both for setting addresses in a more generic API than the ARM-specific one and is useful for save/restore of VGIC state.
Adds KVM_CAP_DEVICE_CTRL to ARM capabilities.
Signed-off-by: Christoffer Dall christoffer.dall@linaro.org
Documentation/virtual/kvm/devices/arm-vgic.txt | 10 +++++++ arch/arm/include/uapi/asm/kvm.h | 8 ++++++ arch/arm/kvm/arm.c | 1 + include/linux/kvm_host.h | 1 + include/uapi/linux/kvm.h | 1 + virt/kvm/arm/vgic.c | 34 ++++++++++++++++++++++++ virt/kvm/kvm_main.c | 4 +++ 7 files changed, 59 insertions(+) create mode 100644 Documentation/virtual/kvm/devices/arm-vgic.txt
diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt new file mode 100644 index 0000000..25fd2d9 --- /dev/null +++ b/Documentation/virtual/kvm/devices/arm-vgic.txt @@ -0,0 +1,10 @@ +MPIC interrupt controller
MPIC?
yes, ARM MPIC, haven't heard of it?
+=========================
+Device types supported:
- KVM_DEV_TYPE_ARM_VGIC ARM Generic Interrupt Controller v2.0
+Only one VGIC instance may be instantiated through either this API or the +legacy KVM_CREATE_IRQCHIP api. The created VGIC will act as the VM interrupt +controller, requiring emulated user-space devices to inject interrupts to the +VGIC instead of directly to CPUs. diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h index c1ee007..587f1ae 100644 --- a/arch/arm/include/uapi/asm/kvm.h +++ b/arch/arm/include/uapi/asm/kvm.h @@ -142,6 +142,14 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_VFP_FPINST 0x1009 #define KVM_REG_ARM_VFP_FPINST2 0x100A
+/* Device Control API: ARM VGIC */ +#define KVM_DEV_ARM_VGIC_GRP_ADDR 0 +#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 +#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2 +#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32 +#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT) +#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0 +#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
Could you please describe the groups in the documentation too?
these defines can go in the other patch
/* KVM_IRQ_LINE irq field index values */ #define KVM_ARM_IRQ_TYPE_SHIFT 24 diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 741f66a..b8e3b6e 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -187,6 +187,7 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_IRQCHIP: r = vgic_present; break;
- case KVM_CAP_DEVICE_CTRL: case KVM_CAP_USER_MEMORY: case KVM_CAP_SYNC_MMU: case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index d9a3c30..e2d6556 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1086,6 +1086,7 @@ struct kvm_device *kvm_device_from_filp(struct file *filp);
extern struct kvm_device_ops kvm_mpic_ops; extern struct kvm_device_ops kvm_xics_ops; +extern struct kvm_device_ops kvm_arm_vgic_ops;
#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index a5c86fc..4f2a4ab 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -839,6 +839,7 @@ struct kvm_device_attr { #define KVM_DEV_TYPE_FSL_MPIC_20 1 #define KVM_DEV_TYPE_FSL_MPIC_42 2 #define KVM_DEV_TYPE_XICS 3 +#define KVM_DEV_TYPE_ARM_VGIC 4
Should this be versioned? Gicv2 is different from v3, no?
yes, we can call it all XXX_VGIC_V2. It just becomes so verbose, but it's really the right thing to do.
Alex
/*
- ioctls for VM fds
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 17c5ac7..b3dcd66 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -1497,3 +1497,37 @@ int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr) mutex_unlock(&kvm->lock); return r; }
+static int vgic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) +{
- return -ENXIO;
+}
+static int vgic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) +{
- return -ENXIO;
+}
+static int vgic_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr) +{
- return -ENXIO;
+}
+static void vgic_destroy(struct kvm_device *dev) +{
- kfree(dev);
+}
+static int vgic_create(struct kvm_device *dev, u32 type) +{
- return kvm_vgic_create(dev->kvm);
+}
+struct kvm_device_ops kvm_arm_vgic_ops = {
- .name = "kvm-arm-vgic",
- .create = vgic_create,
- .destroy = vgic_destroy,
- .set_attr = vgic_set_attr,
- .get_attr = vgic_get_attr,
- .has_attr = vgic_has_attr,
+}; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index b547a1c..774e77c 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2282,6 +2282,10 @@ static int kvm_ioctl_create_device(struct kvm *kvm, ops = &kvm_xics_ops; break; #endif +#ifdef CONFIG_KVM_ARM_VGIC
- case KVM_DEV_TYPE_ARM_VGIC:
ops = &kvm_arm_vgic_ops;
+#endif default: return -ENODEV; } -- 1.7.9.5
kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm
Support setting the distributor and cpu interface base addresses in the VM physical address space through the KVM_{SET,GET}_DEVICE_ATTR API in addition the ARM specific API.
This has the added benefit of being able to share more code in user space and do things in a uniform maner.
Also deprecate the older API at the same time, but backwards compatibility will be maintained.
Signed-off-by: Christoffer Dall christoffer.dall@linaro.org --- Documentation/virtual/kvm/api.txt | 5 +- Documentation/virtual/kvm/devices/arm-vgic.txt | 11 +++ arch/arm/kvm/arm.c | 2 +- include/kvm/arm_vgic.h | 2 +- virt/kvm/arm/vgic.c | 90 ++++++++++++++++++++---- 5 files changed, 95 insertions(+), 15 deletions(-)
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 5f91eda..ea5ec4a 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2305,7 +2305,7 @@ This ioctl returns the guest registers that are supported for the KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.
-4.80 KVM_ARM_SET_DEVICE_ADDR +4.80 KVM_ARM_SET_DEVICE_ADDR (deprecated)
Capability: KVM_CAP_ARM_SET_DEVICE_ADDR Architectures: arm @@ -2342,6 +2342,9 @@ and distributor interface, the ioctl must be called after calling KVM_CREATE_IRQCHIP, but before calling KVM_RUN on any of the VCPUs. Calling this ioctl twice for any of the base addresses will return -EEXIST.
+Note, this IOCTL is deprecated and the more flexible SET/GET_DEVICE_ATTR API +should be used instead. + 4.82 KVM_PPC_RTAS_DEFINE_TOKEN
Capability: KVM_CAP_PPC_RTAS diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt index 25fd2d9..ca83ad8 100644 --- a/Documentation/virtual/kvm/devices/arm-vgic.txt +++ b/Documentation/virtual/kvm/devices/arm-vgic.txt @@ -8,3 +8,14 @@ Only one VGIC instance may be instantiated through either this API or the legacy KVM_CREATE_IRQCHIP api. The created VGIC will act as the VM interrupt controller, requiring emulated user-space devices to inject interrupts to the VGIC instead of directly to CPUs. + +Groups: + KVM_DEV_ARM_VGIC_GRP_ADDR + Attributes: + KVM_VGIC_V2_ADDR_TYPE_DIST (rw, 64-bit) + Base address in the guest physical address space of the GIC distributor + register mappings. + + KVM_VGIC_V2_ADDR_TYPE_CPU (rw, 64-bit) + Base address in the guest physical address space of the GIC virtual cpu + interface register mappings. diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index b8e3b6e..63ddccb 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -768,7 +768,7 @@ static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm, case KVM_ARM_DEVICE_VGIC_V2: if (!vgic_present) return -ENXIO; - return kvm_vgic_set_addr(kvm, type, dev_addr->addr); + return kvm_vgic_addr(kvm, type, &dev_addr->addr, true); default: return -ENODEV; } diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 343744e..5631cfa 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -144,7 +144,7 @@ struct kvm_run; struct kvm_exit_mmio;
#ifdef CONFIG_KVM_ARM_VGIC -int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr); +int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write); int kvm_vgic_hyp_init(void); int kvm_vgic_init(struct kvm *kvm); int kvm_vgic_create(struct kvm *kvm); diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index b3dcd66..8e915b7 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -1457,6 +1457,12 @@ static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr, { int ret;
+ if (addr & ~KVM_PHYS_MASK) + return -E2BIG; + + if (addr & (SZ_4K - 1)) + return -EINVAL; + if (!IS_VGIC_ADDR_UNDEF(*ioaddr)) return -EEXIST; if (addr + size < addr) @@ -1469,26 +1475,41 @@ static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr, return ret; }
-int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr) +/** + * kvm_vgic_addr - set or get vgic VM base addresses + * @kvm: pointer to the vm struct + * @type: the VGIC addr type, one of KVM_VGIC_V2_ADDR_TYPE_XXX + * @addr: pointer to address value + * @write: if true set the address in the VM address space, if false read the + * address + * + * Set or get the vgic base addresses for the distributor and the virtual CPU + * interface in the VM physical address space. These addresses are properties + * of the emulated core/SoC and therefore user space initially knows this + * information. + */ +int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write) { int r = 0; struct vgic_dist *vgic = &kvm->arch.vgic;
- if (addr & ~KVM_PHYS_MASK) - return -E2BIG; - - if (addr & (SZ_4K - 1)) - return -EINVAL; - mutex_lock(&kvm->lock); switch (type) { case KVM_VGIC_V2_ADDR_TYPE_DIST: - r = vgic_ioaddr_assign(kvm, &vgic->vgic_dist_base, - addr, KVM_VGIC_V2_DIST_SIZE); + if (write) { + r = vgic_ioaddr_assign(kvm, &vgic->vgic_dist_base, + *addr, KVM_VGIC_V2_DIST_SIZE); + } else { + *addr = vgic->vgic_dist_base; + } break; case KVM_VGIC_V2_ADDR_TYPE_CPU: - r = vgic_ioaddr_assign(kvm, &vgic->vgic_cpu_base, - addr, KVM_VGIC_V2_CPU_SIZE); + if (write) { + r = vgic_ioaddr_assign(kvm, &vgic->vgic_cpu_base, + *addr, KVM_VGIC_V2_CPU_SIZE); + } else { + *addr = vgic->vgic_cpu_base; + } break; default: r = -ENODEV; @@ -1500,16 +1521,61 @@ int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr)
static int vgic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) { + int r; + + switch (attr->group) { + case KVM_DEV_ARM_VGIC_GRP_ADDR: { + u64 __user *uaddr = (u64 __user *)(long)attr->addr; + u64 addr; + unsigned long type = (unsigned long)attr->attr; + + if (copy_from_user(&addr, uaddr, sizeof(addr))) + return -EFAULT; + + r = kvm_vgic_addr(dev->kvm, type, &addr, true); + return (r == -ENODEV) ? -ENXIO : r; + } + } + return -ENXIO; }
static int vgic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) { - return -ENXIO; + int r = ENXIO; + + switch (attr->group) { + case KVM_DEV_ARM_VGIC_GRP_ADDR: { + u64 __user *uaddr = (u64 __user *)(long)attr->addr; + u64 addr; + unsigned long type = (unsigned long)attr->attr; + + r = kvm_vgic_addr(dev->kvm, type, &addr, false); + if (r) + return (r == -ENODEV) ? -ENXIO : r; + + r = 0; + if (copy_to_user(uaddr, &addr, sizeof(addr))) + return -EFAULT; + } + } + + return r; }
static int vgic_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr) { + phys_addr_t offset; + + switch (attr->group) { + case KVM_DEV_ARM_VGIC_GRP_ADDR: + switch (attr->attr) { + case KVM_VGIC_V2_ADDR_TYPE_DIST: + case KVM_VGIC_V2_ADDR_TYPE_CPU: + return 0; + } + break; + } return -ENXIO; }
Am 11.06.2013 um 06:51 schrieb Christoffer Dall christoffer.dall@linaro.org:
Support setting the distributor and cpu interface base addresses in the VM physical address space through the KVM_{SET,GET}_DEVICE_ATTR API in addition the ARM specific API.
This has the added benefit of being able to share more code in user space and do things in a uniform maner.
Also deprecate the older API at the same time, but backwards compatibility will be maintained.
Signed-off-by: Christoffer Dall christoffer.dall@linaro.org
Documentation/virtual/kvm/api.txt | 5 +- Documentation/virtual/kvm/devices/arm-vgic.txt | 11 +++ arch/arm/kvm/arm.c | 2 +- include/kvm/arm_vgic.h | 2 +- virt/kvm/arm/vgic.c | 90 ++++++++++++++++++++---- 5 files changed, 95 insertions(+), 15 deletions(-)
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 5f91eda..ea5ec4a 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2305,7 +2305,7 @@ This ioctl returns the guest registers that are supported for the KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.
-4.80 KVM_ARM_SET_DEVICE_ADDR +4.80 KVM_ARM_SET_DEVICE_ADDR (deprecated)
Capability: KVM_CAP_ARM_SET_DEVICE_ADDR Architectures: arm @@ -2342,6 +2342,9 @@ and distributor interface, the ioctl must be called after calling KVM_CREATE_IRQCHIP, but before calling KVM_RUN on any of the VCPUs. Calling this ioctl twice for any of the base addresses will return -EEXIST.
+Note, this IOCTL is deprecated and the more flexible SET/GET_DEVICE_ATTR API +should be used instead.
4.82 KVM_PPC_RTAS_DEFINE_TOKEN
Capability: KVM_CAP_PPC_RTAS diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt index 25fd2d9..ca83ad8 100644 --- a/Documentation/virtual/kvm/devices/arm-vgic.txt +++ b/Documentation/virtual/kvm/devices/arm-vgic.txt @@ -8,3 +8,14 @@ Only one VGIC instance may be instantiated through either this API or the legacy KVM_CREATE_IRQCHIP api. The created VGIC will act as the VM interrupt controller, requiring emulated user-space devices to inject interrupts to the VGIC instead of directly to CPUs.
+Groups:
Ah, here they are :)
- KVM_DEV_ARM_VGIC_GRP_ADDR
- Attributes:
- KVM_VGIC_V2_ADDR_TYPE_DIST (rw, 64-bit)
Base address in the guest physical address space of the GIC distributor
register mappings.
- KVM_VGIC_V2_ADDR_TYPE_CPU (rw, 64-bit)
Base address in the guest physical address space of the GIC virtual cpu
interface register mappings.
Is this per-cpu or per-vgic? Can different CPUs have their gic interface maps mapped at different offsets?
Alex
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index b8e3b6e..63ddccb 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -768,7 +768,7 @@ static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm, case KVM_ARM_DEVICE_VGIC_V2: if (!vgic_present) return -ENXIO;
return kvm_vgic_set_addr(kvm, type, dev_addr->addr);
default: return -ENODEV; }return kvm_vgic_addr(kvm, type, &dev_addr->addr, true);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 343744e..5631cfa 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -144,7 +144,7 @@ struct kvm_run; struct kvm_exit_mmio;
#ifdef CONFIG_KVM_ARM_VGIC -int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr); +int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write); int kvm_vgic_hyp_init(void); int kvm_vgic_init(struct kvm *kvm); int kvm_vgic_create(struct kvm *kvm); diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index b3dcd66..8e915b7 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -1457,6 +1457,12 @@ static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr, { int ret;
- if (addr & ~KVM_PHYS_MASK)
return -E2BIG;
- if (addr & (SZ_4K - 1))
return -EINVAL;
- if (!IS_VGIC_ADDR_UNDEF(*ioaddr)) return -EEXIST; if (addr + size < addr)
@@ -1469,26 +1475,41 @@ static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr, return ret; }
-int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr) +/**
- kvm_vgic_addr - set or get vgic VM base addresses
- @kvm: pointer to the vm struct
- @type: the VGIC addr type, one of KVM_VGIC_V2_ADDR_TYPE_XXX
- @addr: pointer to address value
- @write: if true set the address in the VM address space, if false read the
address
- Set or get the vgic base addresses for the distributor and the virtual CPU
- interface in the VM physical address space. These addresses are properties
- of the emulated core/SoC and therefore user space initially knows this
- information.
- */
+int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write) { int r = 0; struct vgic_dist *vgic = &kvm->arch.vgic;
- if (addr & ~KVM_PHYS_MASK)
return -E2BIG;
- if (addr & (SZ_4K - 1))
return -EINVAL;
- mutex_lock(&kvm->lock); switch (type) { case KVM_VGIC_V2_ADDR_TYPE_DIST:
r = vgic_ioaddr_assign(kvm, &vgic->vgic_dist_base,
addr, KVM_VGIC_V2_DIST_SIZE);
if (write) {
r = vgic_ioaddr_assign(kvm, &vgic->vgic_dist_base,
*addr, KVM_VGIC_V2_DIST_SIZE);
} else {
*addr = vgic->vgic_dist_base;
case KVM_VGIC_V2_ADDR_TYPE_CPU:} break;
r = vgic_ioaddr_assign(kvm, &vgic->vgic_cpu_base,
addr, KVM_VGIC_V2_CPU_SIZE);
if (write) {
r = vgic_ioaddr_assign(kvm, &vgic->vgic_cpu_base,
*addr, KVM_VGIC_V2_CPU_SIZE);
} else {
*addr = vgic->vgic_cpu_base;
default: r = -ENODEV;} break;
@@ -1500,16 +1521,61 @@ int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr)
static int vgic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) {
- int r;
- switch (attr->group) {
- case KVM_DEV_ARM_VGIC_GRP_ADDR: {
u64 __user *uaddr = (u64 __user *)(long)attr->addr;
u64 addr;
unsigned long type = (unsigned long)attr->attr;
if (copy_from_user(&addr, uaddr, sizeof(addr)))
return -EFAULT;
r = kvm_vgic_addr(dev->kvm, type, &addr, true);
return (r == -ENODEV) ? -ENXIO : r;
- }
- }
- return -ENXIO;
}
static int vgic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) {
- return -ENXIO;
- int r = ENXIO;
- switch (attr->group) {
- case KVM_DEV_ARM_VGIC_GRP_ADDR: {
u64 __user *uaddr = (u64 __user *)(long)attr->addr;
u64 addr;
unsigned long type = (unsigned long)attr->attr;
r = kvm_vgic_addr(dev->kvm, type, &addr, false);
if (r)
return (r == -ENODEV) ? -ENXIO : r;
r = 0;
if (copy_to_user(uaddr, &addr, sizeof(addr)))
return -EFAULT;
- }
- }
- return r;
}
static int vgic_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr) {
- phys_addr_t offset;
- switch (attr->group) {
- case KVM_DEV_ARM_VGIC_GRP_ADDR:
switch (attr->attr) {
case KVM_VGIC_V2_ADDR_TYPE_DIST:
case KVM_VGIC_V2_ADDR_TYPE_CPU:
return 0;
}
break;
- } return -ENXIO;
}
-- 1.7.9.5
kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm
On Tue, Jun 18, 2013 at 03:25:04PM +0200, Alexander Graf wrote:
Am 11.06.2013 um 06:51 schrieb Christoffer Dall christoffer.dall@linaro.org:
Support setting the distributor and cpu interface base addresses in the VM physical address space through the KVM_{SET,GET}_DEVICE_ATTR API in addition the ARM specific API.
This has the added benefit of being able to share more code in user space and do things in a uniform maner.
Also deprecate the older API at the same time, but backwards compatibility will be maintained.
Signed-off-by: Christoffer Dall christoffer.dall@linaro.org
Documentation/virtual/kvm/api.txt | 5 +- Documentation/virtual/kvm/devices/arm-vgic.txt | 11 +++ arch/arm/kvm/arm.c | 2 +- include/kvm/arm_vgic.h | 2 +- virt/kvm/arm/vgic.c | 90 ++++++++++++++++++++---- 5 files changed, 95 insertions(+), 15 deletions(-)
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 5f91eda..ea5ec4a 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2305,7 +2305,7 @@ This ioctl returns the guest registers that are supported for the KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.
-4.80 KVM_ARM_SET_DEVICE_ADDR +4.80 KVM_ARM_SET_DEVICE_ADDR (deprecated)
Capability: KVM_CAP_ARM_SET_DEVICE_ADDR Architectures: arm @@ -2342,6 +2342,9 @@ and distributor interface, the ioctl must be called after calling KVM_CREATE_IRQCHIP, but before calling KVM_RUN on any of the VCPUs. Calling this ioctl twice for any of the base addresses will return -EEXIST.
+Note, this IOCTL is deprecated and the more flexible SET/GET_DEVICE_ATTR API +should be used instead.
4.82 KVM_PPC_RTAS_DEFINE_TOKEN
Capability: KVM_CAP_PPC_RTAS diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt index 25fd2d9..ca83ad8 100644 --- a/Documentation/virtual/kvm/devices/arm-vgic.txt +++ b/Documentation/virtual/kvm/devices/arm-vgic.txt @@ -8,3 +8,14 @@ Only one VGIC instance may be instantiated through either this API or the legacy KVM_CREATE_IRQCHIP api. The created VGIC will act as the VM interrupt controller, requiring emulated user-space devices to inject interrupts to the VGIC instead of directly to CPUs.
+Groups:
Ah, here they are :)
- KVM_DEV_ARM_VGIC_GRP_ADDR
- Attributes:
- KVM_VGIC_V2_ADDR_TYPE_DIST (rw, 64-bit)
Base address in the guest physical address space of the GIC distributor
register mappings.
- KVM_VGIC_V2_ADDR_TYPE_CPU (rw, 64-bit)
Base address in the guest physical address space of the GIC virtual cpu
interface register mappings.
Is this per-cpu or per-vgic? Can different CPUs have their gic interface maps mapped at different offsets?
This is per-vgic.
If the _CPU part is confusing, it means it's the address of the CPU interface, as opposed to the Distributor interface. Individual CPUs calculate their specific offset from this base address based on a mask, but the base is common for everyone (and banked depending on the accessing CPU for a certain region).
-Christoffer
On 18.06.2013, at 17:46, Christoffer Dall wrote:
On Tue, Jun 18, 2013 at 03:25:04PM +0200, Alexander Graf wrote:
Am 11.06.2013 um 06:51 schrieb Christoffer Dall christoffer.dall@linaro.org:
Support setting the distributor and cpu interface base addresses in the VM physical address space through the KVM_{SET,GET}_DEVICE_ATTR API in addition the ARM specific API.
This has the added benefit of being able to share more code in user space and do things in a uniform maner.
Also deprecate the older API at the same time, but backwards compatibility will be maintained.
Signed-off-by: Christoffer Dall christoffer.dall@linaro.org
Documentation/virtual/kvm/api.txt | 5 +- Documentation/virtual/kvm/devices/arm-vgic.txt | 11 +++ arch/arm/kvm/arm.c | 2 +- include/kvm/arm_vgic.h | 2 +- virt/kvm/arm/vgic.c | 90 ++++++++++++++++++++---- 5 files changed, 95 insertions(+), 15 deletions(-)
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 5f91eda..ea5ec4a 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2305,7 +2305,7 @@ This ioctl returns the guest registers that are supported for the KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.
-4.80 KVM_ARM_SET_DEVICE_ADDR +4.80 KVM_ARM_SET_DEVICE_ADDR (deprecated)
Capability: KVM_CAP_ARM_SET_DEVICE_ADDR Architectures: arm @@ -2342,6 +2342,9 @@ and distributor interface, the ioctl must be called after calling KVM_CREATE_IRQCHIP, but before calling KVM_RUN on any of the VCPUs. Calling this ioctl twice for any of the base addresses will return -EEXIST.
+Note, this IOCTL is deprecated and the more flexible SET/GET_DEVICE_ATTR API +should be used instead.
4.82 KVM_PPC_RTAS_DEFINE_TOKEN
Capability: KVM_CAP_PPC_RTAS diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt index 25fd2d9..ca83ad8 100644 --- a/Documentation/virtual/kvm/devices/arm-vgic.txt +++ b/Documentation/virtual/kvm/devices/arm-vgic.txt @@ -8,3 +8,14 @@ Only one VGIC instance may be instantiated through either this API or the legacy KVM_CREATE_IRQCHIP api. The created VGIC will act as the VM interrupt controller, requiring emulated user-space devices to inject interrupts to the VGIC instead of directly to CPUs.
+Groups:
Ah, here they are :)
- KVM_DEV_ARM_VGIC_GRP_ADDR
- Attributes:
- KVM_VGIC_V2_ADDR_TYPE_DIST (rw, 64-bit)
Base address in the guest physical address space of the GIC distributor
register mappings.
- KVM_VGIC_V2_ADDR_TYPE_CPU (rw, 64-bit)
Base address in the guest physical address space of the GIC virtual cpu
interface register mappings.
Is this per-cpu or per-vgic? Can different CPUs have their gic interface maps mapped at different offsets?
This is per-vgic.
If the _CPU part is confusing, it means it's the address of the CPU interface, as opposed to the Distributor interface. Individual CPUs calculate their specific offset from this base address based on a mask, but the base is common for everyone (and banked depending on the accessing CPU for a certain region).
Ah, that's perfectly fine then. On the MPIC this is part of the normal address space, so I was merely confused on why it has a separate offset. But I guess you can't argue about how hardware works ;).
Alex
Define CPU interface offsets for the GICC_ABPR, GICC_APR, and GICC_IIDR registers. Define distributor registers for the GICD_SPENDSGIR and the GICD_CPENDSGIR. KVM/ARM needs to know about these definitions to fully support save/restore of the VGIC.
Also define some masks and shifts for the various GICH_VMCR fields.
Cc: Thomas Gleixner tglx@linutronix.de Signed-off-by: Christoffer Dall christoffer.dall@linaro.org --- include/linux/irqchip/arm-gic.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 3e203eb..e95c00e 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -17,6 +17,9 @@ #define GIC_CPU_EOI 0x10 #define GIC_CPU_RUNNINGPRI 0x14 #define GIC_CPU_HIGHPRI 0x18 +#define GIC_CPU_ALIAS_BINPOINT 0x1c +#define GIC_CPU_ACTIVEPRIO 0xd0 +#define GIC_CPU_IDENT 0xfc
#define GIC_DIST_CTRL 0x000 #define GIC_DIST_CTR 0x004 @@ -31,6 +34,8 @@ #define GIC_DIST_TARGET 0x800 #define GIC_DIST_CONFIG 0xc00 #define GIC_DIST_SOFTINT 0xf00 +#define GIC_DIST_SGI_CLEAR 0xf10 +#define GIC_DIST_SGI_SET 0xf20
#define GICH_HCR 0x0 #define GICH_VTR 0x4 @@ -54,6 +59,15 @@ #define GICH_LR_ACTIVE_BIT (1 << 29) #define GICH_LR_EOI (1 << 19)
+#define GICH_VMCR_CTRL_SHIFT 0 +#define GICH_VMCR_CTRL_MASK (0x21f << GICH_VMCR_CTRL_SHIFT) +#define GICH_VMCR_PRIMASK_SHIFT 27 +#define GICH_VMCR_PRIMASK_MASK (0x1f << GICH_VMCR_PRIMASK_SHIFT) +#define GICH_VMCR_BINPOINT_SHIFT 21 +#define GICH_VMCR_BINPOINT_MASK (0x7 << GICH_VMCR_BINPOINT_SHIFT) +#define GICH_VMCR_ALIAS_BINPOINT_SHIFT 18 +#define GICH_VMCR_ALIAS_BINPOINT_MASK (0x7 << GICH_VMCR_ALIAS_BINPOINT_SHIFT) + #define GICH_MISR_EOI (1 << 0) #define GICH_MISR_U (1 << 1)
Rename the vgic_ranges array to vgic_dist_ranges to be more specific and to prepare for handling CPU interface register access as well (for save/restore of VGIC state).
Pass offset from distributor or interface MMIO base to find_matching_range function instead of the physical address of the access in the VM memory map. This allows other callers unaware of the VM specifics, but with generic VGIC knowledge to reuse the function.
Signed-off-by: Christoffer Dall christoffer.dall@linaro.org --- virt/kvm/arm/vgic.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 8e915b7..bfb9985 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -604,7 +604,7 @@ struct mmio_range { phys_addr_t offset); };
-static const struct mmio_range vgic_ranges[] = { +static const struct mmio_range vgic_dist_ranges[] = { { .base = GIC_DIST_CTRL, .len = 12, @@ -671,14 +671,13 @@ static const struct mmio_range vgic_ranges[] = { static const struct mmio_range *find_matching_range(const struct mmio_range *ranges, struct kvm_exit_mmio *mmio, - phys_addr_t base) + phys_addr_t offset) { const struct mmio_range *r = ranges; - phys_addr_t addr = mmio->phys_addr - base;
while (r->len) { - if (addr >= r->base && - (addr + mmio->len) <= (r->base + r->len)) + if (offset >= r->base && + (offset + mmio->len) <= (r->base + r->len)) return r; r++; } @@ -715,7 +714,8 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, return true; }
- range = find_matching_range(vgic_ranges, mmio, base); + offset = mmio->phys_addr - base; + range = find_matching_range(vgic_dist_ranges, mmio, offset); if (unlikely(!range || !range->handle_mmio)) { pr_warn("Unhandled access %d %08llx %d\n", mmio->is_write, mmio->phys_addr, mmio->len);
Adds infrastructure to handle distributor and cpu interface register accesses through the KVM_{GET/SET}_DEVICE_ATTR interface by adding the KVM_DEV_ARM_VGIC_GRP_DIST_REGS and KVM_DEV_ARM_VGIC_GRP_CPU_REGS groups and defining the semantics of the attr field to be the MMIO offset as specified in the GICv2 specs.
This does not actually implement missing register accesses to let the full VGIC state be accessible from user space, nor does it handle potential situations where the existing handle_mmio functions are not handling a save/restore scenario well enough, that will come in the following patches.
Signed-off-by: Christoffer Dall christoffer.dall@linaro.org --- Documentation/virtual/kvm/devices/arm-vgic.txt | 31 +++++ virt/kvm/arm/vgic.c | 156 ++++++++++++++++++++++++ 2 files changed, 187 insertions(+)
diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt index ca83ad8..0e70b2c 100644 --- a/Documentation/virtual/kvm/devices/arm-vgic.txt +++ b/Documentation/virtual/kvm/devices/arm-vgic.txt @@ -19,3 +19,34 @@ Groups: KVM_VGIC_V2_ADDR_TYPE_CPU (rw, 64-bit) Base address in the guest physical address space of the GIC virtual cpu interface register mappings. + + KVM_DEV_ARM_VGIC_GRP_DIST_REGS + Attributes: + The attr field of kvm_device_attr encodes two values: + bits: | 63 .... 40 | 39 .. 32 | 31 .... 0 | + values: | reserved | cpu id | offset | + + The offset is relative to the "Distributor base address" as defined in the + GICv2 specs. Getting or setting such a register has the same effect as + reading or writing the register on the actual hardware from the cpu + specified with cpu id field. Note that most distributor fields are not + banked, but return the same value regardless of the cpu id used to access + the register. + Limitations: + - Priorities are not implemented, and registers are RAZ/WI + Errors: + - ENODEV: Getting or setting this register is not yet supported + + KVM_DEV_ARM_VGIC_GRP_CPU_REGS + Attributes: + The attr field of kvm_device_attr encodes two values: + bits: | 63 .... 40 | 39 .. 32 | 31 .... 0 | + values: | reserved | cpu id | offset | + + The offsetspecifies the offset from the "CPU interface base address" as + defined in the GICv2 specs. Getting or setting such a register has the + same effect as reading or writing the register on the actual hardware. + Limitations: + - Priorities are not implemented, and registers are RAZ/WI + Errors: + - ENODEV: Getting or setting this register is not yet supported diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index bfb9985..4821ce9 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -591,11 +591,29 @@ static bool handle_mmio_sgi_reg(struct kvm_vcpu *vcpu, return false; }
+static bool handle_mmio_sgi_clear(struct kvm_vcpu *vcpu, + struct kvm_exit_mmio *mmio, + phys_addr_t offset) +{ + return false; +} + +static bool handle_mmio_sgi_set(struct kvm_vcpu *vcpu, + struct kvm_exit_mmio *mmio, + phys_addr_t offset) +{ + return false; +} + /* * I would have liked to use the kvm_bus_io_*() API instead, but it * cannot cope with banked registers (only the VM pointer is passed * around, and we need the vcpu). One of these days, someone please * fix it! + * + * Note that the handle_mmio implementations should not use the phys_addr + * field from the kvm_exit_mmio struct as this will not have any sane values + * when used to save/restore state from user space. */ struct mmio_range { phys_addr_t base; @@ -665,6 +683,16 @@ static const struct mmio_range vgic_dist_ranges[] = { .len = 4, .handle_mmio = handle_mmio_sgi_reg, }, + { + .base = GIC_DIST_SGI_CLEAR, + .len = VGIC_NR_SGIS / 4, + .handle_mmio = handle_mmio_sgi_clear, + }, + { + .base = GIC_DIST_SGI_SET, + .len = VGIC_NR_SGIS / 4, + .handle_mmio = handle_mmio_sgi_set, + }, {} };
@@ -1519,6 +1547,93 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write) return r; }
+static bool handle_cpu_mmio_misc(struct kvm_vcpu *vcpu, + struct kvm_exit_mmio *mmio, phys_addr_t offset) +{ + return true; +} + +static const struct mmio_range vgic_cpu_ranges[] = { + { + .base = GIC_CPU_CTRL, + .len = 4, + .handle_mmio = handle_cpu_mmio_misc, + }, + { + .base = GIC_CPU_PRIMASK, + .len = 4, + .handle_mmio = handle_cpu_mmio_misc, + }, + { + .base = GIC_CPU_BINPOINT, + .len = 4, + .handle_mmio = handle_cpu_mmio_misc, + }, + { + .base = GIC_CPU_ALIAS_BINPOINT, + .len = 4, + .handle_mmio = handle_cpu_mmio_misc, + }, + { + .base = GIC_CPU_ACTIVEPRIO, + .len = 16, + .handle_mmio = handle_cpu_mmio_misc, + }, + { + .base = GIC_CPU_IDENT, + .len = 4, + .handle_mmio = handle_cpu_mmio_misc, + }, +}; + +static struct kvm_exit_mmio dev_attr_mmio = { .len = 4 }; + +static int vgic_attr_regs_access(struct kvm_device *dev, + struct kvm_device_attr *attr, + u32 *reg, bool is_write) +{ + u32 __user *uaddr = (u32 __user *)(long)attr->addr; + const struct mmio_range *r = NULL; + phys_addr_t offset; + int cpuid; + struct kvm_vcpu *vcpu; + struct kvm_exit_mmio mmio; + + offset = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK; + cpuid = attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK; + + if (cpuid >= atomic_read(&dev->kvm->online_vcpus)) + return -EINVAL; + + vcpu = kvm_get_vcpu(dev->kvm, cpuid); + + mmio.len = 4; + mmio.is_write = is_write; + if (is_write) { + if (copy_from_user(mmio.data, uaddr, sizeof(*uaddr))) + return -EFAULT; + } + + if (attr->group == KVM_DEV_ARM_VGIC_GRP_DIST_REGS) + r = find_matching_range(vgic_dist_ranges, &mmio, offset); + else if (attr->group == KVM_DEV_ARM_VGIC_GRP_DIST_REGS) + r = find_matching_range(vgic_cpu_ranges, &mmio, offset); + + if (unlikely(!r|| !r->handle_mmio)) + return -ENXIO; + + spin_lock(&vcpu->kvm->arch.vgic.lock); + r->handle_mmio(vcpu, &mmio, offset); + spin_unlock(&vcpu->kvm->arch.vgic.lock); + + if (!is_write) { + if (copy_to_user(uaddr, mmio.data, sizeof(*uaddr))) + return -EFAULT; + } + + return 0; +} + static int vgic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) { int r; @@ -1535,6 +1650,18 @@ static int vgic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) r = kvm_vgic_addr(dev->kvm, type, &addr, true); return (r == -ENODEV) ? -ENXIO : r; } + + case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: + case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: { + u32 __user *uaddr = (u32 __user *)(long)attr->addr; + u32 reg; + + if (get_user(reg, uaddr)) + return -EFAULT; + + return vgic_attr_regs_access(dev, attr, ®, true); + } + }
return -ENXIO; @@ -1557,12 +1684,35 @@ static int vgic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) r = 0; if (copy_to_user(uaddr, &addr, sizeof(addr))) return -EFAULT; + break; } + + case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: + case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: { + u32 __user *uaddr = (u32 __user *)(long)attr->addr; + u32 reg = 0; + + r = vgic_attr_regs_access(dev, attr, ®, false); + if (r) + return r; + r = put_user(reg, uaddr); + break; + } + }
return r; }
+static int vgic_has_attr_regs(const struct mmio_range *ranges, + phys_addr_t offset) +{ + if (find_matching_range(ranges, &dev_attr_mmio, offset)) + return 0; + else + return -ENXIO; +} + static int vgic_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr) { phys_addr_t offset; @@ -1575,6 +1725,12 @@ static int vgic_has_attr(struct kvm_device *dev, struct kvm_device_attr *attr) return 0; } break; + case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: + offset = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK; + return vgic_has_attr_regs(vgic_dist_ranges, offset); + case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: + offset = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK; + return vgic_has_attr_regs(vgic_cpu_ranges, offset); } return -ENXIO; }
Handle MMIO accesses to the two registers which should support both the case where the VMs want to read/write either of these registers and the case where user space reads/writes these registers to do save/restore of the VGIC state.
Note that the added complexity compared to simple set/clear enable registers stems from the bookkeping of source cpu ids. It may be possible to change the underlying data structure to simplify the complexity, but since this is not in the critical path, at all, this is left as an interesting excercise to the reader.
Signed-off-by: Christoffer Dall christoffer.dall@linaro.org --- virt/kvm/arm/vgic.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 2 deletions(-)
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 4821ce9..62d0fec 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -591,18 +591,128 @@ static bool handle_mmio_sgi_reg(struct kvm_vcpu *vcpu, return false; }
+static void read_sgi_set_clear(struct kvm_vcpu *vcpu, + struct kvm_exit_mmio *mmio, + phys_addr_t offset) +{ + struct vgic_dist *dist = &vcpu->kvm->arch.vgic; + struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; + int i, sgi, cpu; + int min_sgi = (offset & ~0x3) * 4; + int max_sgi = min_sgi + 3; + int vcpu_id = vcpu->vcpu_id; + u32 lr, reg = 0; + + /* Copy source SGIs from distributor side */ + for (sgi = min_sgi; sgi <= max_sgi; sgi++) { + int shift = 8 * (sgi - min_sgi); + reg |= (u32)dist->irq_sgi_sources[vcpu_id][sgi] << shift; + } + + /* Copy source SGIs already on LRs */ + for_each_set_bit(i, vgic_cpu->lr_used, vgic_cpu->nr_lr) { + lr = vgic_cpu->vgic_lr[i]; + sgi = lr & GICH_LR_VIRTUALID; + cpu = (lr & GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT; + if (sgi >= min_sgi && sgi <= max_sgi) { + if (lr & GICH_LR_STATE) + reg |= (1 << cpu) << (8 * (sgi - min_sgi)); + } + } + + memcpy(mmio->data, ®, sizeof(reg)); +} + static bool handle_mmio_sgi_clear(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, phys_addr_t offset) { - return false; + struct vgic_dist *dist = &vcpu->kvm->arch.vgic; + struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; + int i, sgi, cpu; + int min_sgi = (offset & ~0x3) * 4; + int max_sgi = min_sgi + 3; + int vcpu_id = vcpu->vcpu_id; + u32 *lr, reg; + bool updated = false; + + if (!mmio->is_write) { + read_sgi_set_clear(vcpu, mmio, offset); + return false; + } + + memcpy(®, mmio->data, sizeof(reg)); + + /* Clear pending SGIs on distributor side */ + for (sgi = min_sgi; sgi <= max_sgi; sgi++) { + u8 mask = reg >> (8 * (sgi - min_sgi)); + if (dist->irq_sgi_sources[vcpu_id][sgi] & mask) + updated = true; + dist->irq_sgi_sources[vcpu_id][sgi] &= ~mask; + } + + /* Clear SGIs already on LRs */ + for_each_set_bit(i, vgic_cpu->lr_used, vgic_cpu->nr_lr) { + lr = &vgic_cpu->vgic_lr[i]; + sgi = *lr & GICH_LR_VIRTUALID; + cpu = (*lr & GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT; + + if (sgi >= min_sgi && sgi <= max_sgi) { + if (reg & ((1 << cpu) << (8 * (sgi - min_sgi)))) { + if (*lr & GICH_LR_PENDING_BIT) + updated = true; + *lr &= GICH_LR_PENDING_BIT; + } + } + } + + return updated; }
static bool handle_mmio_sgi_set(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, phys_addr_t offset) { - return false; + struct vgic_dist *dist = &vcpu->kvm->arch.vgic; + struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; + int i, sgi, cpu; + int min_sgi = (offset & ~0x3) * 4; + int max_sgi = min_sgi + 3; + int vcpu_id = vcpu->vcpu_id; + u32 *lr, reg; + bool updated = false; + + if (!mmio->is_write) { + read_sgi_set_clear(vcpu, mmio, offset); + return false; + } + + memcpy(®, mmio->data, sizeof(reg)); + + /* Set pending SGIs on distributor side */ + for (sgi = min_sgi; sgi <= max_sgi; sgi++) { + u8 mask = reg >> (8 * (sgi - min_sgi)); + if ((dist->irq_sgi_sources[vcpu_id][sgi] & mask) != mask) + updated = true; + dist->irq_sgi_sources[vcpu_id][sgi] |= mask; + } + + /* Set active SGIs already on LRs to pending and active */ + for_each_set_bit(i, vgic_cpu->lr_used, vgic_cpu->nr_lr) { + lr = &vgic_cpu->vgic_lr[i]; + sgi = *lr & GICH_LR_VIRTUALID; + cpu = (*lr & GICH_LR_PHYSID_CPUID) >> GICH_LR_PHYSID_CPUID_SHIFT; + + if (sgi >= min_sgi && sgi <= max_sgi) { + if (reg & ((1 << cpu) << (8 * (sgi - min_sgi)))) { + if (!(*lr & GICH_LR_PENDING_BIT)) + updated = true; + *lr |= GICH_LR_PENDING_BIT; + } + } + } + + return updated; }
/*
Implement support for the CPU interface register access driven by MMIO address offsets from the CPU interface base address. Useful for user space to support save/restore of the VGIC state.
This commit adds support only for the same logic as the current VGIC support, and no more. For example, the active priority registers are handled as RAZ/WI, just like setting priorities on the emulated distributor.
Signed-off-by: Christoffer Dall christoffer.dall@linaro.org --- virt/kvm/arm/vgic.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 3 deletions(-)
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 62d0fec..64bea93 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -1660,9 +1660,61 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write) static bool handle_cpu_mmio_misc(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, phys_addr_t offset) { - return true; + struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; + u32 reg, mask = 0, shift = 0; + bool updated = false; + + switch (offset & ~0x3) { + case GIC_CPU_CTRL: + mask = GICH_VMCR_CTRL_MASK; + shift = GICH_VMCR_CTRL_SHIFT; + break; + case GIC_CPU_PRIMASK: + mask = GICH_VMCR_PRIMASK_MASK; + shift = GICH_VMCR_PRIMASK_SHIFT; + break; + case GIC_CPU_BINPOINT: + mask = GICH_VMCR_BINPOINT_MASK; + shift = GICH_VMCR_BINPOINT_SHIFT; + break; + case GIC_CPU_ALIAS_BINPOINT: + mask = GICH_VMCR_ALIAS_BINPOINT_MASK; + shift = GICH_VMCR_ALIAS_BINPOINT_SHIFT; + break; + } + + if (!mmio->is_write) { + reg = (vgic_cpu->vgic_vmcr & mask) >> 0; + memcpy(mmio->data, ®, sizeof(reg)); + } else { + memcpy(®, mmio->data, sizeof(reg)); + reg = (reg << shift) & mask; + if (reg != (vgic_cpu->vgic_vmcr & mask)) + updated = true; + vgic_cpu->vgic_vmcr &= ~mask; + vgic_cpu->vgic_vmcr |= reg; + } + return updated; }
+static bool handle_cpu_mmio_ident(struct kvm_vcpu *vcpu, + struct kvm_exit_mmio *mmio, + phys_addr_t offset) +{ + u32 reg; + + if (mmio->is_write) + return false; + + reg = 0x0002043B; + memcpy(mmio->data, ®, sizeof(reg)); + return false; +} + +/* + * CPU Interface Register accesses - these are not accessed by the VM, but by + * user space for saving and restoring VGIC state. + */ static const struct mmio_range vgic_cpu_ranges[] = { { .base = GIC_CPU_CTRL, @@ -1687,12 +1739,12 @@ static const struct mmio_range vgic_cpu_ranges[] = { { .base = GIC_CPU_ACTIVEPRIO, .len = 16, - .handle_mmio = handle_cpu_mmio_misc, + .handle_mmio = handle_mmio_raz_wi, }, { .base = GIC_CPU_IDENT, .len = 4, - .handle_mmio = handle_cpu_mmio_misc, + .handle_mmio = handle_cpu_mmio_ident, }, };
On 06/11/2013 06:51 AM, Christoffer Dall wrote:
This patch series adds support for user space save/restore of the VGIC state. Instead of expanding the ONE_REG interface, which works on VCPUs, we first introduce support for the new KVM device control API and the VGIC. Now, instead of calling KVM_CREATE_IRQCHIP, user space can call KVM_CREATE_DEVICE and perform operations on the device fd, such as KVM_SET_DEVICE_ATTR to set a device attribute.
We leverage the KVM_{SET/GET}_DEVICE_ATTR API to export the state of the VGIC to user space. Instead of coming up with our own custom format for exporting the VGIC state, we simply export all the state visible to an emulated guest, which must contain the full GIC state to provide save/restore of the GIC state for power management purposes. This further provides the benefit of being able to re-use the MMIO emulation code for the distributor for save/restore.
However, the need to save/restore cpu-specific state demands that user space can save/restore state accessible through the CPU interface, and we therefore add an emulation interface for the CPU-specific interface.
This is considered a first attempt, and I am not married to the device control API. If there are good technical arguments to take another approach, I am of course willing to discuss this. However, my attempts with the ONE_REG interface did not look very nice.
[ WARINING: The patch set core functionality is completely untested; the basic KVM system has been briefly tested on TC2 and it doesn't seem like I've broken existing functionality. ]
I wanted to get this out early to get feedback on the overall API and idea, and I'm writing some user QEMU for the user space side to test the new functionality meanwhile.
Patches are against kvm-arm-next and also available here: git://git.linaro.org/people/cdall/linux-kvm-arm.git vgic-migrate
I don't see major glitches :)
Reviewed-by: Alexander Graf agraf@suse.de
Alex
linaro-kernel@lists.linaro.org