diff options
author | Jason J. Herne <jjherne@linux.vnet.ibm.com> | 2014-11-25 09:46:02 -0500 |
---|---|---|
committer | Christian Borntraeger <borntraeger@de.ibm.com> | 2015-01-23 07:25:40 -0500 |
commit | 72f250206f0f291190ab7f54e4d92ab211779929 (patch) | |
tree | 26e1d8b82e4ff5dd59822f5c849364de4b82d5a1 | |
parent | 556cc0dab1f65f40b755da556a462ae68d6b57a1 (diff) |
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>
-rw-r--r-- | arch/s390/include/asm/kvm_host.h | 1 | ||||
-rw-r--r-- | arch/s390/include/uapi/asm/kvm.h | 5 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 128 |
3 files changed, 134 insertions, 0 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index a2dcd0e099f7..8e22aa0f97fd 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h | |||
@@ -528,6 +528,7 @@ struct kvm_arch{ | |||
528 | struct mutex ipte_mutex; | 528 | struct mutex ipte_mutex; |
529 | spinlock_t start_stop_lock; | 529 | spinlock_t start_stop_lock; |
530 | struct kvm_s390_crypto crypto; | 530 | struct kvm_s390_crypto crypto; |
531 | u64 epoch; | ||
531 | }; | 532 | }; |
532 | 533 | ||
533 | #define KVM_HVA_ERR_BAD (-1UL) | 534 | #define KVM_HVA_ERR_BAD (-1UL) |
diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h index 7e9165e1bec5..cb64319d3e51 100644 --- a/arch/s390/include/uapi/asm/kvm.h +++ b/arch/s390/include/uapi/asm/kvm.h | |||
@@ -57,12 +57,17 @@ struct kvm_s390_io_adapter_req { | |||
57 | 57 | ||
58 | /* kvm attr_group on vm fd */ | 58 | /* kvm attr_group on vm fd */ |
59 | #define KVM_S390_VM_MEM_CTRL 0 | 59 | #define KVM_S390_VM_MEM_CTRL 0 |
60 | #define KVM_S390_VM_TOD 1 | ||
60 | 61 | ||
61 | /* kvm attributes for mem_ctrl */ | 62 | /* kvm attributes for mem_ctrl */ |
62 | #define KVM_S390_VM_MEM_ENABLE_CMMA 0 | 63 | #define KVM_S390_VM_MEM_ENABLE_CMMA 0 |
63 | #define KVM_S390_VM_MEM_CLR_CMMA 1 | 64 | #define KVM_S390_VM_MEM_CLR_CMMA 1 |
64 | #define KVM_S390_VM_MEM_LIMIT_SIZE 2 | 65 | #define KVM_S390_VM_MEM_LIMIT_SIZE 2 |
65 | 66 | ||
67 | /* kvm attributes for KVM_S390_VM_TOD */ | ||
68 | #define KVM_S390_VM_TOD_LOW 0 | ||
69 | #define KVM_S390_VM_TOD_HIGH 1 | ||
70 | |||
66 | /* for KVM_GET_REGS and KVM_SET_REGS */ | 71 | /* for KVM_GET_REGS and KVM_SET_REGS */ |
67 | struct kvm_regs { | 72 | struct kvm_regs { |
68 | /* general purpose regs for s390 */ | 73 | /* general purpose regs for s390 */ |
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 3677b8ca647f..9cf899e9a5d4 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -342,6 +342,113 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att | |||
342 | return ret; | 342 | return ret; |
343 | } | 343 | } |
344 | 344 | ||
345 | static int kvm_s390_set_tod_high(struct kvm *kvm, struct kvm_device_attr *attr) | ||
346 | { | ||
347 | u8 gtod_high; | ||
348 | |||
349 | if (copy_from_user(>od_high, (void __user *)attr->addr, | ||
350 | sizeof(gtod_high))) | ||
351 | return -EFAULT; | ||
352 | |||
353 | if (gtod_high != 0) | ||
354 | return -EINVAL; | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static int kvm_s390_set_tod_low(struct kvm *kvm, struct kvm_device_attr *attr) | ||
360 | { | ||
361 | struct kvm_vcpu *cur_vcpu; | ||
362 | unsigned int vcpu_idx; | ||
363 | u64 host_tod, gtod; | ||
364 | int r; | ||
365 | |||
366 | if (copy_from_user(>od, (void __user *)attr->addr, sizeof(gtod))) | ||
367 | return -EFAULT; | ||
368 | |||
369 | r = store_tod_clock(&host_tod); | ||
370 | if (r) | ||
371 | return r; | ||
372 | |||
373 | mutex_lock(&kvm->lock); | ||
374 | kvm->arch.epoch = gtod - host_tod; | ||
375 | kvm_for_each_vcpu(vcpu_idx, cur_vcpu, kvm) { | ||
376 | cur_vcpu->arch.sie_block->epoch = kvm->arch.epoch; | ||
377 | exit_sie(cur_vcpu); | ||
378 | } | ||
379 | mutex_unlock(&kvm->lock); | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static int kvm_s390_set_tod(struct kvm *kvm, struct kvm_device_attr *attr) | ||
384 | { | ||
385 | int ret; | ||
386 | |||
387 | if (attr->flags) | ||
388 | return -EINVAL; | ||
389 | |||
390 | switch (attr->attr) { | ||
391 | case KVM_S390_VM_TOD_HIGH: | ||
392 | ret = kvm_s390_set_tod_high(kvm, attr); | ||
393 | break; | ||
394 | case KVM_S390_VM_TOD_LOW: | ||
395 | ret = kvm_s390_set_tod_low(kvm, attr); | ||
396 | break; | ||
397 | default: | ||
398 | ret = -ENXIO; | ||
399 | break; | ||
400 | } | ||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | static int kvm_s390_get_tod_high(struct kvm *kvm, struct kvm_device_attr *attr) | ||
405 | { | ||
406 | u8 gtod_high = 0; | ||
407 | |||
408 | if (copy_to_user((void __user *)attr->addr, >od_high, | ||
409 | sizeof(gtod_high))) | ||
410 | return -EFAULT; | ||
411 | |||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | static int kvm_s390_get_tod_low(struct kvm *kvm, struct kvm_device_attr *attr) | ||
416 | { | ||
417 | u64 host_tod, gtod; | ||
418 | int r; | ||
419 | |||
420 | r = store_tod_clock(&host_tod); | ||
421 | if (r) | ||
422 | return r; | ||
423 | |||
424 | gtod = host_tod + kvm->arch.epoch; | ||
425 | if (copy_to_user((void __user *)attr->addr, >od, sizeof(gtod))) | ||
426 | return -EFAULT; | ||
427 | |||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | static int kvm_s390_get_tod(struct kvm *kvm, struct kvm_device_attr *attr) | ||
432 | { | ||
433 | int ret; | ||
434 | |||
435 | if (attr->flags) | ||
436 | return -EINVAL; | ||
437 | |||
438 | switch (attr->attr) { | ||
439 | case KVM_S390_VM_TOD_HIGH: | ||
440 | ret = kvm_s390_get_tod_high(kvm, attr); | ||
441 | break; | ||
442 | case KVM_S390_VM_TOD_LOW: | ||
443 | ret = kvm_s390_get_tod_low(kvm, attr); | ||
444 | break; | ||
445 | default: | ||
446 | ret = -ENXIO; | ||
447 | break; | ||
448 | } | ||
449 | return ret; | ||
450 | } | ||
451 | |||
345 | static int kvm_s390_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr) | 452 | static int kvm_s390_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr) |
346 | { | 453 | { |
347 | int ret; | 454 | int ret; |
@@ -350,6 +457,9 @@ static int kvm_s390_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr) | |||
350 | case KVM_S390_VM_MEM_CTRL: | 457 | case KVM_S390_VM_MEM_CTRL: |
351 | ret = kvm_s390_set_mem_control(kvm, attr); | 458 | ret = kvm_s390_set_mem_control(kvm, attr); |
352 | break; | 459 | break; |
460 | case KVM_S390_VM_TOD: | ||
461 | ret = kvm_s390_set_tod(kvm, attr); | ||
462 | break; | ||
353 | default: | 463 | default: |
354 | ret = -ENXIO; | 464 | ret = -ENXIO; |
355 | break; | 465 | break; |
@@ -366,6 +476,9 @@ static int kvm_s390_vm_get_attr(struct kvm *kvm, struct kvm_device_attr *attr) | |||
366 | case KVM_S390_VM_MEM_CTRL: | 476 | case KVM_S390_VM_MEM_CTRL: |
367 | ret = kvm_s390_get_mem_control(kvm, attr); | 477 | ret = kvm_s390_get_mem_control(kvm, attr); |
368 | break; | 478 | break; |
479 | case KVM_S390_VM_TOD: | ||
480 | ret = kvm_s390_get_tod(kvm, attr); | ||
481 | break; | ||
369 | default: | 482 | default: |
370 | ret = -ENXIO; | 483 | ret = -ENXIO; |
371 | break; | 484 | break; |
@@ -391,6 +504,17 @@ static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) | |||
391 | break; | 504 | break; |
392 | } | 505 | } |
393 | break; | 506 | break; |
507 | case KVM_S390_VM_TOD: | ||
508 | switch (attr->attr) { | ||
509 | case KVM_S390_VM_TOD_LOW: | ||
510 | case KVM_S390_VM_TOD_HIGH: | ||
511 | ret = 0; | ||
512 | break; | ||
513 | default: | ||
514 | ret = -ENXIO; | ||
515 | break; | ||
516 | } | ||
517 | break; | ||
394 | default: | 518 | default: |
395 | ret = -ENXIO; | 519 | ret = -ENXIO; |
396 | break; | 520 | break; |
@@ -541,6 +665,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) | |||
541 | 665 | ||
542 | kvm->arch.css_support = 0; | 666 | kvm->arch.css_support = 0; |
543 | kvm->arch.use_irqchip = 0; | 667 | kvm->arch.use_irqchip = 0; |
668 | kvm->arch.epoch = 0; | ||
544 | 669 | ||
545 | spin_lock_init(&kvm->arch.start_stop_lock); | 670 | spin_lock_init(&kvm->arch.start_stop_lock); |
546 | 671 | ||
@@ -686,6 +811,9 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu) | |||
686 | 811 | ||
687 | void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) | 812 | void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) |
688 | { | 813 | { |
814 | mutex_lock(&vcpu->kvm->lock); | ||
815 | vcpu->arch.sie_block->epoch = vcpu->kvm->arch.epoch; | ||
816 | mutex_unlock(&vcpu->kvm->lock); | ||
689 | if (!kvm_is_ucontrol(vcpu->kvm)) | 817 | if (!kvm_is_ucontrol(vcpu->kvm)) |
690 | vcpu->arch.gmap = vcpu->kvm->arch.gmap; | 818 | vcpu->arch.gmap = vcpu->kvm->arch.gmap; |
691 | } | 819 | } |