KVM: s390: Fixes and cleanups for 5.6 - fix register corruption - ENOTSUPP/EOPNOTSUPP mixed - reset cleanups/fixes - selftests
Unified · Split
| @@ -4177,6 +4177,42 @@ This ioctl issues an ultravisor call to terminate the secure guest, · 4176 unmodified lines | |||
| 4177 | unpins the VPA pages and releases all the device pages that are used to | 4177 | unpins the VPA pages and releases all the device pages that are used to |
| 4178 | track the secure pages by hypervisor. | 4178 | track the secure pages by hypervisor. |
| 4179 | 4179 | ||
| 4180 | 4.122 KVM_S390_NORMAL_RESET | ||
| 4181 | |||
| 4182 | Capability: KVM_CAP_S390_VCPU_RESETS | ||
| 4183 | Architectures: s390 | ||
| 4184 | Type: vcpu ioctl | ||
| 4185 | Parameters: none | ||
| 4186 | Returns: 0 | ||
| 4187 | |||
| 4188 | This ioctl resets VCPU registers and control structures according to | ||
| 4189 | the cpu reset definition in the POP (Principles Of Operation). | ||
| 4190 | |||
| 4191 | 4.123 KVM_S390_INITIAL_RESET | ||
| 4192 | |||
| 4193 | Capability: none | ||
| 4194 | Architectures: s390 | ||
| 4195 | Type: vcpu ioctl | ||
| 4196 | Parameters: none | ||
| 4197 | Returns: 0 | ||
| 4198 | |||
| 4199 | This ioctl resets VCPU registers and control structures according to | ||
| 4200 | the initial cpu reset definition in the POP. However, the cpu is not | ||
| 4201 | put into ESA mode. This reset is a superset of the normal reset. | ||
| 4202 | |||
| 4203 | 4.124 KVM_S390_CLEAR_RESET | ||
| 4204 | |||
| 4205 | Capability: KVM_CAP_S390_VCPU_RESETS | ||
| 4206 | Architectures: s390 | ||
| 4207 | Type: vcpu ioctl | ||
| 4208 | Parameters: none | ||
| 4209 | Returns: 0 | ||
| 4210 | |||
| 4211 | This ioctl resets VCPU registers and control structures according to | ||
| 4212 | the clear cpu reset definition in the POP. However, the cpu is not put | ||
| 4213 | into ESA mode. This reset is a superset of the initial reset. | ||
| 4214 | |||
| 4215 | |||
| 4180 | 5. The kvm_run structure | 4216 | 5. The kvm_run structure |
| 4181 | ------------------------ | 4217 | ------------------------ |
| 4182 | 4218 | ||
| @@ -5405,3 +5441,10 @@ handling by KVM (as some KVM hypercall may be mistakenly treated as TLB · 1222 unmodified lines | |||
| 5405 | flush hypercalls by Hyper-V) so userspace should disable KVM identification | 5441 | flush hypercalls by Hyper-V) so userspace should disable KVM identification |
| 5406 | in CPUID and only exposes Hyper-V identification. In this case, guest | 5442 | in CPUID and only exposes Hyper-V identification. In this case, guest |
| 5407 | thinks it's running on Hyper-V and only use Hyper-V hypercalls. | 5443 | thinks it's running on Hyper-V and only use Hyper-V hypercalls. |
| 5444 | |||
| 5445 | 8.22 KVM_CAP_S390_VCPU_RESETS | ||
| 5446 | |||
| 5447 | Architectures: s390 | ||
| 5448 | |||
| 5449 | This capability indicates that the KVM_S390_NORMAL_RESET and | ||
| 5450 | KVM_S390_CLEAR_RESET ioctls are available. | ||
| @@ -122,6 +122,11 @@ struct mcck_volatile_info { · 121 unmodified lines | |||
| 122 | __u32 reserved; | 122 | __u32 reserved; |
| 123 | }; | 123 | }; |
| 124 | 124 | ||
| 125 | #define CR0_INITIAL_MASK (CR0_UNUSED_56 | CR0_INTERRUPT_KEY_SUBMASK | \ | ||
| 126 | CR0_MEASUREMENT_ALERT_SUBMASK) | ||
| 127 | #define CR14_INITIAL_MASK (CR14_UNUSED_32 | CR14_UNUSED_33 | \ | ||
| 128 | CR14_EXTERNAL_DAMAGE_SUBMASK) | ||
| 129 | |||
| 125 | #define CPUSTAT_STOPPED 0x80000000 | 130 | #define CPUSTAT_STOPPED 0x80000000 |
| 126 | #define CPUSTAT_WAIT 0x10000000 | 131 | #define CPUSTAT_WAIT 0x10000000 |
| 127 | #define CPUSTAT_ECALL_PEND 0x08000000 | 132 | #define CPUSTAT_ECALL_PEND 0x08000000 |
| @@ -2190,7 +2190,7 @@ static int flic_ais_mode_get_all(struct kvm *kvm, struct kvm_device_attr *attr) · 2189 unmodified lines | |||
| 2190 | return -EINVAL; | 2190 | return -EINVAL; |
| 2191 | 2191 | ||
| 2192 | if (!test_kvm_facility(kvm, 72)) | 2192 | if (!test_kvm_facility(kvm, 72)) |
| 2193 | return -ENOTSUPP; | 2193 | return -EOPNOTSUPP; |
| 2194 | 2194 | ||
| 2195 | mutex_lock(&fi->ais_lock); | 2195 | mutex_lock(&fi->ais_lock); |
| 2196 | ais.simm = fi->simm; | 2196 | ais.simm = fi->simm; |
| @@ -2499,7 +2499,7 @@ static int modify_ais_mode(struct kvm *kvm, struct kvm_device_attr *attr) · 302 unmodified lines | |||
| 2499 | int ret = 0; | 2499 | int ret = 0; |
| 2500 | 2500 | ||
| 2501 | if (!test_kvm_facility(kvm, 72)) | 2501 | if (!test_kvm_facility(kvm, 72)) |
| 2502 | return -ENOTSUPP; | 2502 | return -EOPNOTSUPP; |
| 2503 | 2503 | ||
| 2504 | if (copy_from_user(&req, (void __user *)attr->addr, sizeof(req))) | 2504 | if (copy_from_user(&req, (void __user *)attr->addr, sizeof(req))) |
| 2505 | return -EFAULT; | 2505 | return -EFAULT; |
| @@ -2579,7 +2579,7 @@ static int flic_ais_mode_set_all(struct kvm *kvm, struct kvm_device_attr *attr) · 73 unmodified lines | |||
| 2579 | struct kvm_s390_ais_all ais; | 2579 | struct kvm_s390_ais_all ais; |
| 2580 | 2580 | ||
| 2581 | if (!test_kvm_facility(kvm, 72)) | 2581 | if (!test_kvm_facility(kvm, 72)) |
| 2582 | return -ENOTSUPP; | 2582 | return -EOPNOTSUPP; |
| 2583 | 2583 | ||
| 2584 | if (copy_from_user(&ais, (void __user *)attr->addr, sizeof(ais))) | 2584 | if (copy_from_user(&ais, (void __user *)attr->addr, sizeof(ais))) |
| 2585 | return -EFAULT; | 2585 | return -EFAULT; |
| @@ -529,6 +529,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) · 528 unmodified lines | |||
| 529 | case KVM_CAP_S390_CMMA_MIGRATION: | 529 | case KVM_CAP_S390_CMMA_MIGRATION: |
| 530 | case KVM_CAP_S390_AIS: | 530 | case KVM_CAP_S390_AIS: |
| 531 | case KVM_CAP_S390_AIS_MIGRATION: | 531 | case KVM_CAP_S390_AIS_MIGRATION: |
| 532 | case KVM_CAP_S390_VCPU_RESETS: | ||
| 532 | r = 1; | 533 | r = 1; |
| 533 | break; | 534 | break; |
| 534 | case KVM_CAP_S390_HPAGE_1M: | 535 | case KVM_CAP_S390_HPAGE_1M: |
| @@ -2808,35 +2809,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) · 2273 unmodified lines | |||
| 2808 | 2809 | ||
| 2809 | } | 2810 | } |
| 2810 | 2811 | ||
| 2811 | static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu) | ||
| 2812 | { | ||
| 2813 | /* this equals initial cpu reset in pop, but we don't switch to ESA */ | ||
| 2814 | vcpu->arch.sie_block->gpsw.mask = 0UL; | ||
| 2815 | vcpu->arch.sie_block->gpsw.addr = 0UL; | ||
| 2816 | kvm_s390_set_prefix(vcpu, 0); | ||
| 2817 | kvm_s390_set_cpu_timer(vcpu, 0); | ||
| 2818 | vcpu->arch.sie_block->ckc = 0UL; | ||
| 2819 | vcpu->arch.sie_block->todpr = 0; | ||
| 2820 | memset(vcpu->arch.sie_block->gcr, 0, 16 * sizeof(__u64)); | ||
| 2821 | vcpu->arch.sie_block->gcr[0] = CR0_UNUSED_56 | | ||
| 2822 | CR0_INTERRUPT_KEY_SUBMASK | | ||
| 2823 | CR0_MEASUREMENT_ALERT_SUBMASK; | ||
| 2824 | vcpu->arch.sie_block->gcr[14] = CR14_UNUSED_32 | | ||
| 2825 | CR14_UNUSED_33 | | ||
| 2826 | CR14_EXTERNAL_DAMAGE_SUBMASK; | ||
| 2827 | /* make sure the new fpc will be lazily loaded */ | ||
| 2828 | save_fpu_regs(); | ||
| 2829 | current->thread.fpu.fpc = 0; | ||
| 2830 | vcpu->arch.sie_block->gbea = 1; | ||
| 2831 | vcpu->arch.sie_block->pp = 0; | ||
| 2832 | vcpu->arch.sie_block->fpf &= ~FPF_BPBC; | ||
| 2833 | vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID; | ||
| 2834 | kvm_clear_async_pf_completion_queue(vcpu); | ||
| 2835 | if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm)) | ||
| 2836 | kvm_s390_vcpu_stop(vcpu); | ||
| 2837 | kvm_s390_clear_local_irqs(vcpu); | ||
| 2838 | } | ||
| 2839 | |||
| 2840 | void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) | 2812 | void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) |
| 2841 | { | 2813 | { |
| 2842 | mutex_lock(&vcpu->kvm->lock); | 2814 | mutex_lock(&vcpu->kvm->lock); |
| @@ -3279,10 +3251,53 @@ static int kvm_arch_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, · 436 unmodified lines | |||
| 3279 | return r; | 3251 | return r; |
| 3280 | } | 3252 | } |
| 3281 | 3253 | ||
| 3282 | static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu) | 3254 | static void kvm_arch_vcpu_ioctl_normal_reset(struct kvm_vcpu *vcpu) |
| 3283 | { | 3255 | { |
| 3284 | kvm_s390_vcpu_initial_reset(vcpu); | 3256 | vcpu->arch.sie_block->gpsw.mask &= ~PSW_MASK_RI; |
| 3285 | return 0; | 3257 | vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID; |
| 3258 | memset(vcpu->run->s.regs.riccb, 0, sizeof(vcpu->run->s.regs.riccb)); | ||
| 3259 | |||
| 3260 | kvm_clear_async_pf_completion_queue(vcpu); | ||
| 3261 | if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm)) | ||
| 3262 | kvm_s390_vcpu_stop(vcpu); | ||
| 3263 | kvm_s390_clear_local_irqs(vcpu); | ||
| 3264 | } | ||
| 3265 | |||
| 3266 | static void kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu) | ||
| 3267 | { | ||
| 3268 | /* Initial reset is a superset of the normal reset */ | ||
| 3269 | kvm_arch_vcpu_ioctl_normal_reset(vcpu); | ||
| 3270 | |||
| 3271 | /* this equals initial cpu reset in pop, but we don't switch to ESA */ | ||
| 3272 | vcpu->arch.sie_block->gpsw.mask = 0; | ||
| 3273 | vcpu->arch.sie_block->gpsw.addr = 0; | ||
| 3274 | kvm_s390_set_prefix(vcpu, 0); | ||
| 3275 | kvm_s390_set_cpu_timer(vcpu, 0); | ||
| 3276 | vcpu->arch.sie_block->ckc = 0; | ||
| 3277 | vcpu->arch.sie_block->todpr = 0; | ||
| 3278 | memset(vcpu->arch.sie_block->gcr, 0, sizeof(vcpu->arch.sie_block->gcr)); | ||
| 3279 | vcpu->arch.sie_block->gcr[0] = CR0_INITIAL_MASK; | ||
| 3280 | vcpu->arch.sie_block->gcr[14] = CR14_INITIAL_MASK; | ||
| 3281 | vcpu->run->s.regs.fpc = 0; | ||
| 3282 | vcpu->arch.sie_block->gbea = 1; | ||
| 3283 | vcpu->arch.sie_block->pp = 0; | ||
| 3284 | vcpu->arch.sie_block->fpf &= ~FPF_BPBC; | ||
| 3285 | } | ||
| 3286 | |||
| 3287 | static void kvm_arch_vcpu_ioctl_clear_reset(struct kvm_vcpu *vcpu) | ||
| 3288 | { | ||
| 3289 | struct kvm_sync_regs *regs = &vcpu->run->s.regs; | ||
| 3290 | |||
| 3291 | /* Clear reset is a superset of the initial reset */ | ||
| 3292 | kvm_arch_vcpu_ioctl_initial_reset(vcpu); | ||
| 3293 | |||
| 3294 | memset(®s->gprs, 0, sizeof(regs->gprs)); | ||
| 3295 | memset(®s->vrs, 0, sizeof(regs->vrs)); | ||
| 3296 | memset(®s->acrs, 0, sizeof(regs->acrs)); | ||
| 3297 | memset(®s->gscb, 0, sizeof(regs->gscb)); | ||
| 3298 | |||
| 3299 | regs->etoken = 0; | ||
| 3300 | regs->etoken_extension = 0; | ||
| 3286 | } | 3301 | } |
| 3287 | 3302 | ||
| 3288 | int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | 3303 | int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) |
| @@ -4343,7 +4358,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, · 1054 unmodified lines | |||
| 4343 | switch (ioctl) { | 4358 | switch (ioctl) { |
| 4344 | case KVM_S390_STORE_STATUS: | 4359 | case KVM_S390_STORE_STATUS: |
| 4345 | idx = srcu_read_lock(&vcpu->kvm->srcu); | 4360 | idx = srcu_read_lock(&vcpu->kvm->srcu); |
| 4346 | r = kvm_s390_vcpu_store_status(vcpu, arg); | 4361 | r = kvm_s390_store_status_unloaded(vcpu, arg); |
| 4347 | srcu_read_unlock(&vcpu->kvm->srcu, idx); | 4362 | srcu_read_unlock(&vcpu->kvm->srcu, idx); |
| 4348 | break; | 4363 | break; |
| 4349 | case KVM_S390_SET_INITIAL_PSW: { | 4364 | case KVM_S390_SET_INITIAL_PSW: { |
| @@ -4355,8 +4370,17 @@ long kvm_arch_vcpu_ioctl(struct file *filp, · 5 unmodified lines | |||
| 4355 | r = kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw); | 4370 | r = kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw); |
| 4356 | break; | 4371 | break; |
| 4357 | } | 4372 | } |
| 4373 | case KVM_S390_CLEAR_RESET: | ||
| 4374 | r = 0; | ||
| 4375 | kvm_arch_vcpu_ioctl_clear_reset(vcpu); | ||
| 4376 | break; | ||
| 4358 | case KVM_S390_INITIAL_RESET: | 4377 | case KVM_S390_INITIAL_RESET: |
| 4359 | r = kvm_arch_vcpu_ioctl_initial_reset(vcpu); | 4378 | r = 0; |
| 4379 | kvm_arch_vcpu_ioctl_initial_reset(vcpu); | ||
| 4380 | break; | ||
| 4381 | case KVM_S390_NORMAL_RESET: | ||
| 4382 | r = 0; | ||
| 4383 | kvm_arch_vcpu_ioctl_normal_reset(vcpu); | ||
| 4360 | break; | 4384 | break; |
| 4361 | case KVM_SET_ONE_REG: | 4385 | case KVM_SET_ONE_REG: |
| 4362 | case KVM_GET_ONE_REG: { | 4386 | case KVM_GET_ONE_REG: { |
| @@ -1009,6 +1009,7 @@ struct kvm_ppc_resize_hpt { · 1008 unmodified lines | |||
| 1009 | #define KVM_CAP_PPC_GUEST_DEBUG_SSTEP 176 | 1009 | #define KVM_CAP_PPC_GUEST_DEBUG_SSTEP 176 |
| 1010 | #define KVM_CAP_ARM_NISV_TO_USER 177 | 1010 | #define KVM_CAP_ARM_NISV_TO_USER 177 |
| 1011 | #define KVM_CAP_ARM_INJECT_EXT_DABT 178 | 1011 | #define KVM_CAP_ARM_INJECT_EXT_DABT 178 |
| 1012 | #define KVM_CAP_S390_VCPU_RESETS 179 | ||
| 1012 | 1013 | ||
| 1013 | #ifdef KVM_CAP_IRQ_ROUTING | 1014 | #ifdef KVM_CAP_IRQ_ROUTING |
| 1014 | 1015 | ||
| @@ -1473,6 +1474,10 @@ struct kvm_enc_region { · 458 unmodified lines | |||
| 1473 | /* Available with KVM_CAP_ARM_SVE */ | 1474 | /* Available with KVM_CAP_ARM_SVE */ |
| 1474 | #define KVM_ARM_VCPU_FINALIZE _IOW(KVMIO, 0xc2, int) | 1475 | #define KVM_ARM_VCPU_FINALIZE _IOW(KVMIO, 0xc2, int) |
| 1475 | 1476 | ||
| 1477 | /* Available with KVM_CAP_S390_VCPU_RESETS */ | ||
| 1478 | #define KVM_S390_NORMAL_RESET _IO(KVMIO, 0xc3) | ||
| 1479 | #define KVM_S390_CLEAR_RESET _IO(KVMIO, 0xc4) | ||
| 1480 | |||
| 1476 | /* Secure Encrypted Virtualization command */ | 1481 | /* Secure Encrypted Virtualization command */ |
| 1477 | enum sev_cmd_id { | 1482 | enum sev_cmd_id { |
| 1478 | /* Guest initialization commands */ | 1483 | /* Guest initialization commands */ |
| @@ -36,6 +36,7 @@ TEST_GEN_PROGS_aarch64 += kvm_create_max_vcpus · 35 unmodified lines | |||
| 36 | 36 | ||
| 37 | TEST_GEN_PROGS_s390x = s390x/memop | 37 | TEST_GEN_PROGS_s390x = s390x/memop |
| 38 | TEST_GEN_PROGS_s390x += s390x/sync_regs_test | 38 | TEST_GEN_PROGS_s390x += s390x/sync_regs_test |
| 39 | TEST_GEN_PROGS_s390x += s390x/resets | ||
| 39 | TEST_GEN_PROGS_s390x += dirty_log_test | 40 | TEST_GEN_PROGS_s390x += dirty_log_test |
| 40 | TEST_GEN_PROGS_s390x += kvm_create_max_vcpus | 41 | TEST_GEN_PROGS_s390x += kvm_create_max_vcpus |
| 41 | 42 | ||
| @@ -125,6 +125,12 @@ void vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, · 124 unmodified lines | |||
| 125 | struct kvm_sregs *sregs); | 125 | struct kvm_sregs *sregs); |
| 126 | int _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, | 126 | int _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, |
| 127 | struct kvm_sregs *sregs); | 127 | struct kvm_sregs *sregs); |
| 128 | void vcpu_fpu_get(struct kvm_vm *vm, uint32_t vcpuid, | ||
| 129 | struct kvm_fpu *fpu); | ||
| 130 | void vcpu_fpu_set(struct kvm_vm *vm, uint32_t vcpuid, | ||
| 131 | struct kvm_fpu *fpu); | ||
| 132 | void vcpu_get_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg); | ||
| 133 | void vcpu_set_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg); | ||
| 128 | #ifdef __KVM_HAVE_VCPU_EVENTS | 134 | #ifdef __KVM_HAVE_VCPU_EVENTS |
| 129 | void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, | 135 | void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, |
| 130 | struct kvm_vcpu_events *events); | 136 | struct kvm_vcpu_events *events); |
| @@ -1373,6 +1373,42 @@ int _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs) · 1372 unmodified lines | |||
| 1373 | return ioctl(vcpu->fd, KVM_SET_SREGS, sregs); | 1373 | return ioctl(vcpu->fd, KVM_SET_SREGS, sregs); |
| 1374 | } | 1374 | } |
| 1375 | 1375 | ||
| 1376 | void vcpu_fpu_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_fpu *fpu) | ||
| 1377 | { | ||
| 1378 | int ret; | ||
| 1379 | |||
| 1380 | ret = _vcpu_ioctl(vm, vcpuid, KVM_GET_FPU, fpu); | ||
| 1381 | TEST_ASSERT(ret == 0, "KVM_GET_FPU failed, rc: %i errno: %i (%s)", | ||
| 1382 | ret, errno, strerror(errno)); | ||
| 1383 | } | ||
| 1384 | |||
| 1385 | void vcpu_fpu_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_fpu *fpu) | ||
| 1386 | { | ||
| 1387 | int ret; | ||
| 1388 | |||
| 1389 | ret = _vcpu_ioctl(vm, vcpuid, KVM_SET_FPU, fpu); | ||
| 1390 | TEST_ASSERT(ret == 0, "KVM_SET_FPU failed, rc: %i errno: %i (%s)", | ||
| 1391 | ret, errno, strerror(errno)); | ||
| 1392 | } | ||
| 1393 | |||
| 1394 | void vcpu_get_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg) | ||
| 1395 | { | ||
| 1396 | int ret; | ||
| 1397 | |||
| 1398 | ret = _vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, reg); | ||
| 1399 | TEST_ASSERT(ret == 0, "KVM_GET_ONE_REG failed, rc: %i errno: %i (%s)", | ||
| 1400 | ret, errno, strerror(errno)); | ||
| 1401 | } | ||
| 1402 | |||
| 1403 | void vcpu_set_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg) | ||
| 1404 | { | ||
| 1405 | int ret; | ||
| 1406 | |||
| 1407 | ret = _vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, reg); | ||
| 1408 | TEST_ASSERT(ret == 0, "KVM_SET_ONE_REG failed, rc: %i errno: %i (%s)", | ||
| 1409 | ret, errno, strerror(errno)); | ||
| 1410 | } | ||
| 1411 | |||
| 1376 | /* | 1412 | /* |
| 1377 | * VCPU Ioctl | 1413 | * VCPU Ioctl |
| 1378 | * | 1414 | * |
| @@ -0,0 +1,197 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 2 | /* | ||
| 3 | * Test for s390x CPU resets | ||
| 4 | * | ||
| 5 | * Copyright (C) 2020, IBM | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <stdio.h> | ||
| 9 | #include <stdlib.h> | ||
| 10 | #include <string.h> | ||
| 11 | #include <sys/ioctl.h> | ||
| 12 | |||
| 13 | #include "test_util.h" | ||
| 14 | #include "kvm_util.h" | ||
| 15 | |||
| 16 | #define VCPU_ID 3 | ||
| 17 | #define LOCAL_IRQS 32 | ||
| 18 | |||
| 19 | struct kvm_s390_irq buf[VCPU_ID + LOCAL_IRQS]; | ||
| 20 | |||
| 21 | struct kvm_vm *vm; | ||
| 22 | struct kvm_run *run; | ||
| 23 | struct kvm_sync_regs *regs; | ||
| 24 | static uint64_t regs_null[16]; | ||
| 25 | |||
| 26 | static uint64_t crs[16] = { 0x40000ULL, | ||
| 27 | 0x42000ULL, | ||
| 28 | 0, 0, 0, 0, 0, | ||
| 29 | 0x43000ULL, | ||
| 30 | 0, 0, 0, 0, 0, | ||
| 31 | 0x44000ULL, | ||
| 32 | 0, 0 | ||
| 33 | }; | ||
| 34 | |||
| 35 | static void guest_code_initial(void) | ||
| 36 | { | ||
| 37 | /* Round toward 0 */ | ||
| 38 | uint32_t fpc = 0x11; | ||
| 39 | |||
| 40 | /* Dirty registers */ | ||
| 41 | asm volatile ( | ||
| 42 | " lctlg 0,15,%0\n" | ||
| 43 | " sfpc %1\n" | ||
| 44 | : : "Q" (crs), "d" (fpc)); | ||
| 45 | GUEST_SYNC(0); | ||
| 46 | } | ||
| 47 | |||
| 48 | static void test_one_reg(uint64_t id, uint64_t value) | ||
| 49 | { | ||
| 50 | struct kvm_one_reg reg; | ||
| 51 | uint64_t eval_reg; | ||
| 52 | |||
| 53 | reg.addr = (uintptr_t)&eval_reg; | ||
| 54 | reg.id = id; | ||
| 55 | vcpu_get_reg(vm, VCPU_ID, ®); | ||
| 56 | TEST_ASSERT(eval_reg == value, "value == %s", value); | ||
| 57 | } | ||
| 58 | |||
| 59 | static void assert_noirq(void) | ||
| 60 | { | ||
| 61 | struct kvm_s390_irq_state irq_state; | ||
| 62 | int irqs; | ||
| 63 | |||
| 64 | irq_state.len = sizeof(buf); | ||
| 65 | irq_state.buf = (unsigned long)buf; | ||
| 66 | irqs = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_GET_IRQ_STATE, &irq_state); | ||
| 67 | /* | ||
| 68 | * irqs contains the number of retrieved interrupts. Any interrupt | ||
| 69 | * (notably, the emergency call interrupt we have injected) should | ||
| 70 | * be cleared by the resets, so this should be 0. | ||
| 71 | */ | ||
| 72 | TEST_ASSERT(irqs >= 0, "Could not fetch IRQs: errno %d\n", errno); | ||
| 73 | TEST_ASSERT(!irqs, "IRQ pending"); | ||
| 74 | } | ||
| 75 | |||
| 76 | static void assert_clear(void) | ||
| 77 | { | ||
| 78 | struct kvm_sregs sregs; | ||
| 79 | struct kvm_regs regs; | ||
| 80 | struct kvm_fpu fpu; | ||
| 81 | |||
| 82 | vcpu_regs_get(vm, VCPU_ID, ®s); | ||
| 83 | TEST_ASSERT(!memcmp(®s.gprs, regs_null, sizeof(regs.gprs)), "grs == 0"); | ||
| 84 | |||
| 85 | vcpu_sregs_get(vm, VCPU_ID, &sregs); | ||
| 86 | TEST_ASSERT(!memcmp(&sregs.acrs, regs_null, sizeof(sregs.acrs)), "acrs == 0"); | ||
| 87 | |||
| 88 | vcpu_fpu_get(vm, VCPU_ID, &fpu); | ||
| 89 | TEST_ASSERT(!memcmp(&fpu.fprs, regs_null, sizeof(fpu.fprs)), "fprs == 0"); | ||
| 90 | } | ||
| 91 | |||
| 92 | static void assert_initial(void) | ||
| 93 | { | ||
| 94 | struct kvm_sregs sregs; | ||
| 95 | struct kvm_fpu fpu; | ||
| 96 | |||
| 97 | vcpu_sregs_get(vm, VCPU_ID, &sregs); | ||
| 98 | TEST_ASSERT(sregs.crs[0] == 0xE0UL, "cr0 == 0xE0"); | ||
| 99 | TEST_ASSERT(sregs.crs[14] == 0xC2000000UL, "cr14 == 0xC2000000"); | ||
| 100 | TEST_ASSERT(!memcmp(&sregs.crs[1], regs_null, sizeof(sregs.crs[1]) * 12), | ||
| 101 | "cr1-13 == 0"); | ||
| 102 | TEST_ASSERT(sregs.crs[15] == 0, "cr15 == 0"); | ||
| 103 | |||
| 104 | vcpu_fpu_get(vm, VCPU_ID, &fpu); | ||
| 105 | TEST_ASSERT(!fpu.fpc, "fpc == 0"); | ||
| 106 | |||
| 107 | test_one_reg(KVM_REG_S390_GBEA, 1); | ||
| 108 | test_one_reg(KVM_REG_S390_PP, 0); | ||
| 109 | test_one_reg(KVM_REG_S390_TODPR, 0); | ||
| 110 | test_one_reg(KVM_REG_S390_CPU_TIMER, 0); | ||
| 111 | test_one_reg(KVM_REG_S390_CLOCK_COMP, 0); | ||
| 112 | } | ||
| 113 | |||
| 114 | static void assert_normal(void) | ||
| 115 | { | ||
| 116 | test_one_reg(KVM_REG_S390_PFTOKEN, KVM_S390_PFAULT_TOKEN_INVALID); | ||
| 117 | assert_noirq(); | ||
| 118 | } | ||
| 119 | |||
| 120 | static void inject_irq(int cpu_id) | ||
| 121 | { | ||
| 122 | struct kvm_s390_irq_state irq_state; | ||
| 123 | struct kvm_s390_irq *irq = &buf[0]; | ||
| 124 | int irqs; | ||
| 125 | |||
| 126 | /* Inject IRQ */ | ||
| 127 | irq_state.len = sizeof(struct kvm_s390_irq); | ||
| 128 | irq_state.buf = (unsigned long)buf; | ||
| 129 | irq->type = KVM_S390_INT_EMERGENCY; | ||
| 130 | irq->u.emerg.code = cpu_id; | ||
| 131 | irqs = _vcpu_ioctl(vm, cpu_id, KVM_S390_SET_IRQ_STATE, &irq_state); | ||
| 132 | TEST_ASSERT(irqs >= 0, "Error injecting EMERGENCY IRQ errno %d\n", errno); | ||
| 133 | } | ||
| 134 | |||
| 135 | static void test_normal(void) | ||
| 136 | { | ||
| 137 | printf("Testing normal reset\n"); | ||
| 138 | /* Create VM */ | ||
| 139 | vm = vm_create_default(VCPU_ID, 0, guest_code_initial); | ||
| 140 | run = vcpu_state(vm, VCPU_ID); | ||
| 141 | regs = &run->s.regs; | ||
| 142 | |||
| 143 | vcpu_run(vm, VCPU_ID); | ||
| 144 | |||
| 145 | inject_irq(VCPU_ID); | ||
| 146 | |||
| 147 | vcpu_ioctl(vm, VCPU_ID, KVM_S390_NORMAL_RESET, 0); | ||
| 148 | assert_normal(); | ||
| 149 | kvm_vm_free(vm); | ||
| 150 | } | ||
| 151 | |||
| 152 | static void test_initial(void) | ||
| 153 | { | ||
| 154 | printf("Testing initial reset\n"); | ||
| 155 | vm = vm_create_default(VCPU_ID, 0, guest_code_initial); | ||
| 156 | run = vcpu_state(vm, VCPU_ID); | ||
| 157 | regs = &run->s.regs; | ||
| 158 | |||
| 159 | vcpu_run(vm, VCPU_ID); | ||
| 160 | |||
| 161 | inject_irq(VCPU_ID); | ||
| 162 | |||
| 163 | vcpu_ioctl(vm, VCPU_ID, KVM_S390_INITIAL_RESET, 0); | ||
| 164 | assert_normal(); | ||
| 165 | assert_initial(); | ||
| 166 | kvm_vm_free(vm); | ||
| 167 | } | ||
| 168 | |||
| 169 | static void test_clear(void) | ||
| 170 | { | ||
| 171 | printf("Testing clear reset\n"); | ||
| 172 | vm = vm_create_default(VCPU_ID, 0, guest_code_initial); | ||
| 173 | run = vcpu_state(vm, VCPU_ID); | ||
| 174 | regs = &run->s.regs; | ||
| 175 | |||
| 176 | vcpu_run(vm, VCPU_ID); | ||
| 177 | |||
| 178 | inject_irq(VCPU_ID); | ||
| 179 | |||
| 180 | vcpu_ioctl(vm, VCPU_ID, KVM_S390_CLEAR_RESET, 0); | ||
| 181 | assert_normal(); | ||
| 182 | assert_initial(); | ||
| 183 | assert_clear(); | ||
| 184 | kvm_vm_free(vm); | ||
| 185 | } | ||
| 186 | |||
| 187 | int main(int argc, char *argv[]) | ||
| 188 | { | ||
| 189 | setbuf(stdout, NULL); /* Tell stdout not to buffer its content */ | ||
| 190 | |||
| 191 | test_initial(); | ||
| 192 | if (kvm_check_cap(KVM_CAP_S390_VCPU_RESETS)) { | ||
| 193 | test_normal(); | ||
| 194 | test_clear(); | ||
| 195 | } | ||
| 196 | return 0; | ||
| 197 | } | ||