gpa_t kvm_init_stolen_time(struct kvm_vcpu *vcpu);
 void kvm_update_stolen_time(struct kvm_vcpu *vcpu);
 
+int kvm_arm_pvtime_set_attr(struct kvm_vcpu *vcpu,
+                           struct kvm_device_attr *attr);
+int kvm_arm_pvtime_get_attr(struct kvm_vcpu *vcpu,
+                           struct kvm_device_attr *attr);
+int kvm_arm_pvtime_has_attr(struct kvm_vcpu *vcpu,
+                           struct kvm_device_attr *attr);
+
 static inline void kvm_arm_pvtime_vcpu_init(struct kvm_vcpu_arch *vcpu_arch)
 {
        vcpu_arch->steal.base = GPA_INVALID;
 
 #define KVM_ARM_VCPU_TIMER_CTRL                1
 #define   KVM_ARM_VCPU_TIMER_IRQ_VTIMER                0
 #define   KVM_ARM_VCPU_TIMER_IRQ_PTIMER                1
+#define KVM_ARM_VCPU_PVTIME_CTRL       2
+#define   KVM_ARM_VCPU_PVTIME_IPA      0
 
 /* KVM_IRQ_LINE irq field index values */
 #define KVM_ARM_IRQ_VCPU2_SHIFT                28
 
        case KVM_ARM_VCPU_TIMER_CTRL:
                ret = kvm_arm_timer_set_attr(vcpu, attr);
                break;
+       case KVM_ARM_VCPU_PVTIME_CTRL:
+               ret = kvm_arm_pvtime_set_attr(vcpu, attr);
+               break;
        default:
                ret = -ENXIO;
                break;
        case KVM_ARM_VCPU_TIMER_CTRL:
                ret = kvm_arm_timer_get_attr(vcpu, attr);
                break;
+       case KVM_ARM_VCPU_PVTIME_CTRL:
+               ret = kvm_arm_pvtime_get_attr(vcpu, attr);
+               break;
        default:
                ret = -ENXIO;
                break;
        case KVM_ARM_VCPU_TIMER_CTRL:
                ret = kvm_arm_timer_has_attr(vcpu, attr);
                break;
+       case KVM_ARM_VCPU_PVTIME_CTRL:
+               ret = kvm_arm_pvtime_has_attr(vcpu, attr);
+               break;
        default:
                ret = -ENXIO;
                break;
 
 #define KVM_DEV_TYPE_ARM_VGIC_ITS      KVM_DEV_TYPE_ARM_VGIC_ITS
        KVM_DEV_TYPE_XIVE,
 #define KVM_DEV_TYPE_XIVE              KVM_DEV_TYPE_XIVE
+       KVM_DEV_TYPE_ARM_PV_TIME,
+#define KVM_DEV_TYPE_ARM_PV_TIME       KVM_DEV_TYPE_ARM_PV_TIME
        KVM_DEV_TYPE_MAX,
 };
 
 
 // Copyright (C) 2019 Arm Ltd.
 
 #include <linux/arm-smccc.h>
+#include <linux/kvm_host.h>
 
+#include <asm/kvm_mmu.h>
 #include <asm/pvclock-abi.h>
 
 #include <kvm/arm_hypercalls.h>
 
        return base;
 }
+
+int kvm_arm_pvtime_set_attr(struct kvm_vcpu *vcpu,
+                           struct kvm_device_attr *attr)
+{
+       u64 __user *user = (u64 __user *)attr->addr;
+       struct kvm *kvm = vcpu->kvm;
+       u64 ipa;
+       int ret = 0;
+       int idx;
+
+       if (attr->attr != KVM_ARM_VCPU_PVTIME_IPA)
+               return -ENXIO;
+
+       if (get_user(ipa, user))
+               return -EFAULT;
+       if (!IS_ALIGNED(ipa, 64))
+               return -EINVAL;
+       if (vcpu->arch.steal.base != GPA_INVALID)
+               return -EEXIST;
+
+       /* Check the address is in a valid memslot */
+       idx = srcu_read_lock(&kvm->srcu);
+       if (kvm_is_error_hva(gfn_to_hva(kvm, ipa >> PAGE_SHIFT)))
+               ret = -EINVAL;
+       srcu_read_unlock(&kvm->srcu, idx);
+
+       if (!ret)
+               vcpu->arch.steal.base = ipa;
+
+       return ret;
+}
+
+int kvm_arm_pvtime_get_attr(struct kvm_vcpu *vcpu,
+                           struct kvm_device_attr *attr)
+{
+       u64 __user *user = (u64 __user *)attr->addr;
+       u64 ipa;
+
+       if (attr->attr != KVM_ARM_VCPU_PVTIME_IPA)
+               return -ENXIO;
+
+       ipa = vcpu->arch.steal.base;
+
+       if (put_user(ipa, user))
+               return -EFAULT;
+       return 0;
+}
+
+int kvm_arm_pvtime_has_attr(struct kvm_vcpu *vcpu,
+                           struct kvm_device_attr *attr)
+{
+       switch (attr->attr) {
+       case KVM_ARM_VCPU_PVTIME_IPA:
+               return 0;
+       }
+       return -ENXIO;
+}