mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
KVM: s390: Provide guest TOD Clock Get/Set Controls
Provide controls for setting/getting the guest TOD clock based on the VM attribute interface. Provide TOD and TOD_HIGH vm attributes on s390 for managing guest Time Of Day clock value. TOD_HIGH is presently always set to 0. In the future it will contain a high order expansion of the tod clock value after it overflows the 64-bits of the TOD. Signed-off-by: Jason J. Herne <jjherne@linux.vnet.ibm.com> Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
This commit is contained in:
parent
556cc0dab1
commit
72f250206f
3 changed files with 134 additions and 0 deletions
|
@ -528,6 +528,7 @@ struct kvm_arch{
|
||||||
struct mutex ipte_mutex;
|
struct mutex ipte_mutex;
|
||||||
spinlock_t start_stop_lock;
|
spinlock_t start_stop_lock;
|
||||||
struct kvm_s390_crypto crypto;
|
struct kvm_s390_crypto crypto;
|
||||||
|
u64 epoch;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define KVM_HVA_ERR_BAD (-1UL)
|
#define KVM_HVA_ERR_BAD (-1UL)
|
||||||
|
|
|
@ -57,12 +57,17 @@ struct kvm_s390_io_adapter_req {
|
||||||
|
|
||||||
/* kvm attr_group on vm fd */
|
/* kvm attr_group on vm fd */
|
||||||
#define KVM_S390_VM_MEM_CTRL 0
|
#define KVM_S390_VM_MEM_CTRL 0
|
||||||
|
#define KVM_S390_VM_TOD 1
|
||||||
|
|
||||||
/* kvm attributes for mem_ctrl */
|
/* kvm attributes for mem_ctrl */
|
||||||
#define KVM_S390_VM_MEM_ENABLE_CMMA 0
|
#define KVM_S390_VM_MEM_ENABLE_CMMA 0
|
||||||
#define KVM_S390_VM_MEM_CLR_CMMA 1
|
#define KVM_S390_VM_MEM_CLR_CMMA 1
|
||||||
#define KVM_S390_VM_MEM_LIMIT_SIZE 2
|
#define KVM_S390_VM_MEM_LIMIT_SIZE 2
|
||||||
|
|
||||||
|
/* kvm attributes for KVM_S390_VM_TOD */
|
||||||
|
#define KVM_S390_VM_TOD_LOW 0
|
||||||
|
#define KVM_S390_VM_TOD_HIGH 1
|
||||||
|
|
||||||
/* for KVM_GET_REGS and KVM_SET_REGS */
|
/* for KVM_GET_REGS and KVM_SET_REGS */
|
||||||
struct kvm_regs {
|
struct kvm_regs {
|
||||||
/* general purpose regs for s390 */
|
/* general purpose regs for s390 */
|
||||||
|
|
|
@ -342,6 +342,113 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int kvm_s390_set_tod_high(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
|
{
|
||||||
|
u8 gtod_high;
|
||||||
|
|
||||||
|
if (copy_from_user(>od_high, (void __user *)attr->addr,
|
||||||
|
sizeof(gtod_high)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (gtod_high != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvm_s390_set_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
|
{
|
||||||
|
struct kvm_vcpu *cur_vcpu;
|
||||||
|
unsigned int vcpu_idx;
|
||||||
|
u64 host_tod, gtod;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (copy_from_user(>od, (void __user *)attr->addr, sizeof(gtod)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
r = store_tod_clock(&host_tod);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
mutex_lock(&kvm->lock);
|
||||||
|
kvm->arch.epoch = gtod - host_tod;
|
||||||
|
kvm_for_each_vcpu(vcpu_idx, cur_vcpu, kvm) {
|
||||||
|
cur_vcpu->arch.sie_block->epoch = kvm->arch.epoch;
|
||||||
|
exit_sie(cur_vcpu);
|
||||||
|
}
|
||||||
|
mutex_unlock(&kvm->lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvm_s390_set_tod(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (attr->flags)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch (attr->attr) {
|
||||||
|
case KVM_S390_VM_TOD_HIGH:
|
||||||
|
ret = kvm_s390_set_tod_high(kvm, attr);
|
||||||
|
break;
|
||||||
|
case KVM_S390_VM_TOD_LOW:
|
||||||
|
ret = kvm_s390_set_tod_low(kvm, attr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -ENXIO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvm_s390_get_tod_high(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
|
{
|
||||||
|
u8 gtod_high = 0;
|
||||||
|
|
||||||
|
if (copy_to_user((void __user *)attr->addr, >od_high,
|
||||||
|
sizeof(gtod_high)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvm_s390_get_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
|
{
|
||||||
|
u64 host_tod, gtod;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = store_tod_clock(&host_tod);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
gtod = host_tod + kvm->arch.epoch;
|
||||||
|
if (copy_to_user((void __user *)attr->addr, >od, sizeof(gtod)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvm_s390_get_tod(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (attr->flags)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch (attr->attr) {
|
||||||
|
case KVM_S390_VM_TOD_HIGH:
|
||||||
|
ret = kvm_s390_get_tod_high(kvm, attr);
|
||||||
|
break;
|
||||||
|
case KVM_S390_VM_TOD_LOW:
|
||||||
|
ret = kvm_s390_get_tod_low(kvm, attr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -ENXIO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int kvm_s390_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr)
|
static int kvm_s390_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -350,6 +457,9 @@ static int kvm_s390_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
case KVM_S390_VM_MEM_CTRL:
|
case KVM_S390_VM_MEM_CTRL:
|
||||||
ret = kvm_s390_set_mem_control(kvm, attr);
|
ret = kvm_s390_set_mem_control(kvm, attr);
|
||||||
break;
|
break;
|
||||||
|
case KVM_S390_VM_TOD:
|
||||||
|
ret = kvm_s390_set_tod(kvm, attr);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
break;
|
break;
|
||||||
|
@ -366,6 +476,9 @@ static int kvm_s390_vm_get_attr(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
case KVM_S390_VM_MEM_CTRL:
|
case KVM_S390_VM_MEM_CTRL:
|
||||||
ret = kvm_s390_get_mem_control(kvm, attr);
|
ret = kvm_s390_get_mem_control(kvm, attr);
|
||||||
break;
|
break;
|
||||||
|
case KVM_S390_VM_TOD:
|
||||||
|
ret = kvm_s390_get_tod(kvm, attr);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
break;
|
break;
|
||||||
|
@ -391,6 +504,17 @@ static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case KVM_S390_VM_TOD:
|
||||||
|
switch (attr->attr) {
|
||||||
|
case KVM_S390_VM_TOD_LOW:
|
||||||
|
case KVM_S390_VM_TOD_HIGH:
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -ENXIO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
break;
|
break;
|
||||||
|
@ -541,6 +665,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
||||||
|
|
||||||
kvm->arch.css_support = 0;
|
kvm->arch.css_support = 0;
|
||||||
kvm->arch.use_irqchip = 0;
|
kvm->arch.use_irqchip = 0;
|
||||||
|
kvm->arch.epoch = 0;
|
||||||
|
|
||||||
spin_lock_init(&kvm->arch.start_stop_lock);
|
spin_lock_init(&kvm->arch.start_stop_lock);
|
||||||
|
|
||||||
|
@ -686,6 +811,9 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
|
void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
|
mutex_lock(&vcpu->kvm->lock);
|
||||||
|
vcpu->arch.sie_block->epoch = vcpu->kvm->arch.epoch;
|
||||||
|
mutex_unlock(&vcpu->kvm->lock);
|
||||||
if (!kvm_is_ucontrol(vcpu->kvm))
|
if (!kvm_is_ucontrol(vcpu->kvm))
|
||||||
vcpu->arch.gmap = vcpu->kvm->arch.gmap;
|
vcpu->arch.gmap = vcpu->kvm->arch.gmap;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue