KVM: ARM: Introduce KVM_ARM_SET_DEVICE_ADDR ioctl
authorChristoffer Dall <c.dall@virtualopensystems.com>
Wed, 23 Jan 2013 18:18:04 +0000 (13:18 -0500)
committerMarc Zyngier <marc.zyngier@arm.com>
Mon, 11 Feb 2013 18:58:39 +0000 (18:58 +0000)
On ARM some bits are specific to the model being emulated for the guest and
user space needs a way to tell the kernel about those bits.  An example is mmio
device base addresses, where KVM must know the base address for a given device
to properly emulate mmio accesses within a certain address range or directly
map a device with virtualiation extensions into the guest address space.

We make this API ARM-specific as we haven't yet reached a consensus for a
generic API for all KVM architectures that will allow us to do something like
this.

Reviewed-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Documentation/virtual/kvm/api.txt
arch/arm/include/uapi/asm/kvm.h
arch/arm/kvm/arm.c
include/uapi/linux/kvm.h

index c25439a5827414435e5a7597ec60697437fc0894..4505f869e4500ae8da751192d5313a2993069bf4 100644 (file)
@@ -2210,6 +2210,43 @@ 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
+
+Capability: KVM_CAP_ARM_SET_DEVICE_ADDR
+Architectures: arm
+Type: vm ioctl
+Parameters: struct kvm_arm_device_address (in)
+Returns: 0 on success, -1 on error
+Errors:
+  ENODEV: The device id is unknown
+  ENXIO:  Device not supported on current system
+  EEXIST: Address already set
+  E2BIG:  Address outside guest physical address space
+
+struct kvm_arm_device_addr {
+       __u64 id;
+       __u64 addr;
+};
+
+Specify a device address in the guest's physical address space where guests
+can access emulated or directly exposed devices, which the host kernel needs
+to know about. The id field is an architecture specific identifier for a
+specific device.
+
+ARM divides the id field into two parts, a device id and an address type id
+specific to the individual device.
+
+  bits:  | 63        ...       32 | 31    ...    16 | 15    ...    0 |
+  field: |        0x00000000      |     device id   |  addr type id  |
+
+ARM currently only require this when using the in-kernel GIC support for the
+hardware VGIC features, using KVM_ARM_DEVICE_VGIC_V2 as the device id.  When
+setting the base address for the guest's mapping of the VGIC virtual CPU
+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.
+
+
 5. The kvm_run structure
 ------------------------
 
index 3303ff5adbf3528fa155605d724bb48c32355ca3..346ac3f4a2b8f25987a4c94cd9bf06f146817cdc 100644 (file)
@@ -65,6 +65,19 @@ struct kvm_regs {
 #define KVM_ARM_TARGET_CORTEX_A15      0
 #define KVM_ARM_NUM_TARGETS            1
 
+/* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */
+#define KVM_ARM_DEVICE_TYPE_SHIFT      0
+#define KVM_ARM_DEVICE_TYPE_MASK       (0xffff << KVM_ARM_DEVICE_TYPE_SHIFT)
+#define KVM_ARM_DEVICE_ID_SHIFT                16
+#define KVM_ARM_DEVICE_ID_MASK         (0xffff << KVM_ARM_DEVICE_ID_SHIFT)
+
+/* Supported device IDs */
+#define KVM_ARM_DEVICE_VGIC_V2         0
+
+/* Supported VGIC address types  */
+#define KVM_VGIC_V2_ADDR_TYPE_DIST     0
+#define KVM_VGIC_V2_ADDR_TYPE_CPU      1
+
 #define KVM_ARM_VCPU_POWER_OFF         0 /* CPU is started in OFF state */
 
 struct kvm_vcpu_init {
index 2d30e3afdaf99a01c764b0ac1e557c63f7a639b2..523f77a44e44ef5db9a6b71b685cd90a43654267 100644 (file)
@@ -167,6 +167,8 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_COALESCED_MMIO:
                r = KVM_COALESCED_MMIO_PAGE_OFFSET;
                break;
+       case KVM_CAP_ARM_SET_DEVICE_ADDR:
+               r = 1;
        case KVM_CAP_NR_VCPUS:
                r = num_online_cpus();
                break;
@@ -827,10 +829,29 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
        return -EINVAL;
 }
 
+static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
+                                       struct kvm_arm_device_addr *dev_addr)
+{
+       return -ENODEV;
+}
+
 long kvm_arch_vm_ioctl(struct file *filp,
                       unsigned int ioctl, unsigned long arg)
 {
-       return -EINVAL;
+       struct kvm *kvm = filp->private_data;
+       void __user *argp = (void __user *)arg;
+
+       switch (ioctl) {
+       case KVM_ARM_SET_DEVICE_ADDR: {
+               struct kvm_arm_device_addr dev_addr;
+
+               if (copy_from_user(&dev_addr, argp, sizeof(dev_addr)))
+                       return -EFAULT;
+               return kvm_vm_ioctl_set_device_addr(kvm, &dev_addr);
+       }
+       default:
+               return -EINVAL;
+       }
 }
 
 static void cpu_init_hyp_mode(void *vector)
index 7f2360a46fc2ab691a13f4c65ae1a92a4757aec2..c70577cf67bc23b03fdb48c1caf5911e64e787bd 100644 (file)
@@ -637,6 +637,7 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_PPC_BOOKE_WATCHDOG 83
 #define KVM_CAP_PPC_HTAB_FD 84
 #define KVM_CAP_ARM_PSCI 87
+#define KVM_CAP_ARM_SET_DEVICE_ADDR 88
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -784,6 +785,11 @@ struct kvm_msi {
        __u8  pad[16];
 };
 
+struct kvm_arm_device_addr {
+       __u64 id;
+       __u64 addr;
+};
+
 /*
  * ioctls for VM fds
  */
@@ -869,6 +875,8 @@ struct kvm_s390_ucas_mapping {
 #define KVM_ALLOCATE_RMA         _IOR(KVMIO,  0xa9, struct kvm_allocate_rma)
 /* Available with KVM_CAP_PPC_HTAB_FD */
 #define KVM_PPC_GET_HTAB_FD      _IOW(KVMIO,  0xaa, struct kvm_get_htab_fd)
+/* Available with KVM_CAP_ARM_SET_DEVICE_ADDR */
+#define KVM_ARM_SET_DEVICE_ADDR          _IOW(KVMIO,  0xab, struct kvm_arm_device_addr)
 
 /*
  * ioctls for vcpu fds